链表操作 -- 有环链表问题

参考:

  http://blog.163.com/[email protected]/blog/static/1113522592011828104617420/

问题:

  判断一个链表中是否有环。

分析:

  我们都知道,当一个链表中没有环时,我们使用一个指针能从头遍历到尾;当链表中有环时,链表会在环中旋转。

  当我们只使用一个链表指针时,可想到方法就是使用额外的数据结构来存储遍历过的每个节点,在遍历next节点时,判断next节点是否已存在于存储的节点中。

  存储结构可以选择为hashTable,这样的话,总体的时间复杂度为O(n),空间复杂度为O(n)。

  当我们使用两个指针时【链表操作的常用技巧!】,可以设置快、慢两个指针。

  如果链表中不存在环,快指针肯定最终变为NULL;存在环的话,快指针和慢指针都会进入到环中,因为慢指针相对快指针静止,快指针相对对慢指针步伐为1,最终快指针一定能赶上慢指针。

  此方法时间复杂度为O(n),空间复杂度为O(1)

解答:

  1)使用hashTable,在此不表。

  2)使用快、慢指针。

  

bool isHasCycle(Node* head) const
{
    if(head == NULL || head->next == NULL)
        return false;

    Node* slow = head;
    Node* fast = head->next;

    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;

        if(fast == slow)
            return true;
    }

    return false;
}

问题:

  寻找一个有环链表的第一个入环节点。

分析:

  1)使用hashTable存储已遍历节点的方法中,获取入环节点的时间复杂度为O(n),空间复杂度为O(n)。

  2)当我们使用快慢指针时,两个节点会相遇。

  

  假设直线阶段长度为L,两个指针的相遇点距环的起始点距离为T,这个环的长度为S。

  我们让慢指针从head处开始运动,每次向前走一步;快指针从head->next处开始运动,每次向前走两步。

  当两个指针相遇时,快指针旋转了m圈,慢指针旋转了n圈。

    (L + m×S + T - 1) / 2 = (L + n×S + T) 【时间相同】

  => (m - 2×n)×S = T + L + 1

  => (m - 2×n - 1)×S + S - T = L + 1

    显然,相遇后,让一个指针从链表起始处开始运动,另一个指针从相遇点的下一个节点开始运动。这样,两个指针会在链表的起始节点相遇。

Node* first_Node_in_cycle(Node* head) const
{
    if(head == NULL || head->next == NULL)
        return false;

    Node* slow = head;
    Node* fast = head->next;

    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;

        if(fast == slow)
            break;
    }

    fast = fast->next;
    slow = head;

    while(fast != slow)
    {
        fast = fast->next;
        slow = slow->next;
    }

    return fast;
}

  问题:

    求有环链表的环的长度。

  

  解答:

    在前两问的基础之上。

    1)在使用hashTable时,求解过程显而易见。

    2)使用快、慢指针时,我们可以在指针相遇后,固定一个指针,然另一个指针运动。当两个指针再次相遇时,就是一圈的距离。

      时间复杂度O(n),空间复杂度O(1)。

时间: 2024-10-05 18:31:18

链表操作 -- 有环链表问题的相关文章

链表操作 -- 两个链表间的相交性问题

本文参考: http://blog.csdn.net/g_brightboy/article/details/6824834 http://blog.csdn.net/huangxy10/article/details/8014233 在此致谢. 问题: 给定两个链表,判断它们是否相交. 注意: 如果两个链表相交的话,则公用相交点开始往后的所有节点.[因为节点的next指针只有一个!] 解答: 1)首先来看最直观的方法,也就是一次判断链表A中的节点是否在链表B中出现. 时间复杂度:O(n2) 空

关于相交链表、带环链表、链表深拷贝的思路整理

返回相交链表的交点:1.先求出两个链表的各自长度2.让长的先走他们的(长度差)步3.然后两者同时走,第一次相遇就是交点(返回该结点) 判断链表是否带环:1.快慢指针(快的走两步,慢的走一步,不能一个一步,一个n步(N>2),可能会错过)2.如果两个指针相遇,则链表带环:如果快的遇到null,则不带环(直线形) 求入环点:1).转化为相交问题(求取相遇结点)2).一个从起点,一个从交点,都每次走一步,第一次相遇点为入环点 相交+带环(六种情况) 复杂链表的复制1)简单复制无法解决(因为是浅拷贝)2

链表操作 -- 未排序链表的处理问题

问题: 删除未排序链表中的重复元素. 解答: 1)最朴素的方法就是将链表排序,然后遍历并删除其中的重复元素.这种方法的时间复杂度依赖于排序的过程. 在此,我们要思考一下,找到并且删除链表中的重复元素真的需要排序过程吗? 2)如何才能在不排序的情况下找到重复元素? 最朴素的方法就是处理每个节点的时候,遍历剩余的节点,查看其中是否有重复的元素.这种方法的时间复杂度较高,O(n2). 有没有更好的算法或是数据结构来帮助我们降低这个时间复杂度?这种查找某个元素的存在性问题,可以借助于hash表来快速的实

复习下C 链表操作(单向链表)

Object-C 作为C 的包装语言(运行时.消息机制).如果不熟悉C 的话实在玩得太肤浅. 随便深入oc 内部都会接触到C. runtime .GCD.Block.消息机制... 所有强大的功能无不用的 包装体(struct 结构体).使用GCC/Clang (可以google 下.Clang 比GCC 更优化,) 编译指令. 转换OC 为 C . 终端 使用Clang 命令参考 clang -rewrite-objc file.m 查看file.cpp 文件为编译转换的C 单向链表 创建 .

10、单链表操作

单链表操作 单链表操作1 /*单链表的类型定义*/ typedef int DataType; typedef struct node { DataType data; struct node * next; }LinkNode, *LinkList; /*单链表的定位运算*/ LinkNode *Locate(LinkNode *L, int k)//????为什么此处是LinkNode *Locate()类型,表示什么意思 { LinkNode *p; int i; i= 1; p = L-

JAVA 链表操作:循环链表

主要分析示例: 一.单链表循环链表 二.双链表循环链表 其中单链表节点和双链表节点类和接口ICommOperate<T>与上篇一致,这里不在赘述.参考:JAVA链表操作:单链表和双链表http://www.cnblogs.com/xiaoxing/p/5969133.html 一.单链表循环链表 package LinkListTest; import java.util.HashMap; import java.util.Map; public class SingleCycleLinkLi

判断链表是否有环及两链表是否相交

单向链表是最常用的数据结构之一,因此总结其常见的问题及其解决方案是很有意义的. 问题1:如何判断一个单向链表是否有环?如果有,如何找到其入口节点的指针? 算法思想:用两个指针p1,p2同时指向链表的头部,p1一次移动一步,p2一次移动两步,如果最终p1和p2重合则说明链表有环,如果p2走到空指针(链表的结尾)则说明链表无环: 如果最终p1和p2重合,使p2重新指向链表的头结点,然后p1和p2同时一次移动一步,当p1和p2再次重合时该节点指针就是环的入口节点指针. 算法实现: [cpp] view

单链表的经典操作,查找链表倒数第k个节点,判断链表是否存在环,求环节点

#include<stdio.h>#include<stdlib.h> typedef struct date_list{    int data;    struct date_list* next;}mylist; mylist* creatlist(int x,mylist* p)        //用一个元素创建链表{    if(NULL == p)                         //链表创建必须判空    {        p = malloc(siz

[算法天地]关于单链表的操作有环无环判断

#include <stdio.h> #include <stdlib.h> // 有环链表的各种函数测试 typedef struct Node { int data; struct Node *next; }Node; typedef struct Node* LinkList; /*链表初始化*/ int InitList(LinkList *L) { *L = (LinkList)malloc(sizeof(Node)); if(!(*L)) return -1; (*L)