LeeCode-141/142-环形链表I/IIC++

141 环形链表I

题目描述

在这里插入图片描述

思路 哈希/快慢指针

面经里面的常驻军,好早之前就打算做,一直拖到今天才做
哈希就没啥好说的了,用insert的第二个返回的参数second判断是否插入失败,或者用哈希集合的count判断是否大于0都行
而快慢指针的话,快指针每次移动两位,慢指针每次移动一位,这样在环中每次差一步,一定能追上慢指针
快慢指针需要注意:如果初始都设为head,如果while循环的终止条件为fast == slow,那么第一次进去就结束了,所以至少应该进行一次移动后再判定。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 //存储结点,寻找重复结点,用hashmap、set都行
class Solution {
    
    
public:
    bool hasCycle(ListNode *head) {
    
    
        unordered_set<ListNode*> seen;
        while (head != nullptr) {
    
    
            if (seen.count(head)) {
    
    
                return true;
            }
            seen.insert(head);
            head = head->next;
        }
        return false;
    }
};
//快慢指针
class Solution {
    
    
public:
    bool hasCycle(ListNode *head) {
    
    
        if(head == nullptr || head -> next == nullptr) {
    
    
            return false;
        }
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast && fast ->next) {
    
    
            slow = slow -> next;
            fast = fast -> next -> next;
            if(fast == slow) {
    
    
                return true;
            }
        }
        return false;
    }
};

142 环形链表II

题目描述

在这里插入图片描述

思路 双指针

需要找到环的入口位置。
这就需要我们对快慢指针走了多少步有清楚的认识。
设快指针走f步,慢指针走s步。我们同样使快指针每次走两步,慢指针走一步,显而易见f = 2s。
当相遇的时候,快指针会多走慢指针n倍环的距离,设环长度为b,则f = s + nb
联立可得 s = nb f = 2nb
那么我们就可以得知,相遇的时候s处于nb位置,且我们设环之前的长度a,能够得知环的入口地址为a + nb(n∈R)处(此n非彼n)
所以我们只要让慢指针再走a步即可。但现在问题是a是未知的,所以再次利用双指针,设一个新的指针指向head结点,两边都移动a的时候就会在环开头相遇。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 //用快慢指针必须知道相遇的地方在哪
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        if(head == nullptr || head -> next == nullptr) {
    
    
            return nullptr;
        }
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast -> next) {
    
    
            fast = fast -> next -> next;
            slow = slow -> next;
            if(fast == slow) {
    
    
                fast = head;
                while(fast != slow) {
    
    
                slow = slow -> next;
                fast = fast -> next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};

这里要注意的是,可能存在没有环的情况,如果把两个while循环拆开,进行下一个循环要判断一下fast或者fast -> next是否为空


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 //用快慢指针必须知道相遇的地方在哪
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        if(head == nullptr || head -> next == nullptr) {
    
    
            return nullptr;
        }
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast -> next) {
    
    
            fast = fast -> next -> next;
            slow = slow -> next;
            if(fast == slow) {
    
    
                break;
            }
        }
        if(fast == nullptr || fast -> next == nullptr ) return nullptr;
        fast = head;
        while(fast != slow) {
    
    
            slow = slow -> next;
            fast = fast -> next;
        }
        return fast;
    }
};

因为fast会一下移动两个位置,所以可能本身就是空,也可能下一个位置为空。最好还是按照第一种写,以防自己忘记。
时间复杂度O(n)
空间复杂度O(1)

猜你喜欢

转载自blog.csdn.net/qq_42883222/article/details/114691747