• [LeetCode]环链表相关的题目和算法


    这篇文章讨论一下与链表的环相关的题目,我目前遇到的一共有3种题目。

    1.判断一个链表是否有环(LeetCode相关题目:https://leetcode.com/problems/linked-list-cycle/description/)

    设置两个指针,初始值都指向头,一快一慢,slow每次前进一步,fast每次前进两步,假如链表存在环,两个指针必定会相遇。假如fast走到尾部,则为无环链表。

    代码如下:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        bool hasCycle(ListNode *head) {
            ListNode *fast = head;
            ListNode *slow = head;
            while (fast && fast->next) {
                fast = fast->next->next;
                slow = slow->next;
                if (slow == fast) {
                    return true;
                }
            }
            return false;
        }
    };

     2.判断一个有环链表中环的位置(LeetCode相关题目:https://leetcode.com/problems/linked-list-cycle-ii/description/)

    也是利用到一快一慢的两个指针,借用网上一个图:

    两个指针顺时针走动,fast一次走两步,slow一次走一步,假设两个指针第一次在Z相遇,slow走过的距离为a+b,fast走过的距离为a+b+c+b,2(a + b) == a + b + c + b,得出a == c,因此此时将fast指针放回起点,将两次走一步改为一次走一步。此时,fast和slow同时开始走,由于他们的路程和速度都一样,因此他们会在环的起点相遇。

    代码如下:

    /**
     * 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) {
            ListNode *slow = head;
            ListNode *fast = head;
            while (true) {
                if (fast == NULL || fast->next == NULL) return NULL;
                else {
                    fast = fast->next->next;
                    slow = slow->next;
                    if (fast == slow) break;
                }
            }
            fast = head;
            while (fast != slow) {
                slow = slow->next;
                fast = fast->next;
            }
            return slow;
        }
    };

    3.求两个链表的交点(LeetCode相关题目:https://leetcode.com/problems/intersection-of-two-linked-lists/description/)

    尽管看上去和链表的环没啥关系,但是这个题目可以用这种方法来做。我们可以先将其中一个环的头尾相连,然后按照上一题的做法,就可以找到交点的位置了。不过要记得将一切复原,也就是将环解开。

    代码如下:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
            if (headA == NULL || headB == NULL) return NULL;
            ListNode *copyA = headA;
            ListNode *copyB = headB;
            while (headA->next != NULL) {
                headA = headA->next;
            }
            ListNode *recover = headA; 
            headA->next = copyA;
            ListNode *fast = headB;
            ListNode *slow = headB;
            while (true) {
                if (!fast || !fast->next) {
                    recover->next = NULL;
                    headA = copyA;
                    headB = copyB;
                    return NULL;
                }
                fast = fast->next->next;
                slow = slow->next;
                if (fast == slow) break;
            }
            fast = headB;
            while (fast != slow) {
                slow = slow->next;
                fast = fast->next;
            }
            recover->next = NULL;
            headA = copyA;
            headB = copyB;
            return slow;
        }
    };

    4.其他的。。。

    我能想到的其他题目类型:

    求环的长度:在2的前提下,从环的起点开始,一个指针不动,一个指针走,统计走的长度,两个指针重新相遇时的长度就是环的长度

    将环解开:原理其实一样

    因此,这类题目的关键是利用一快一慢两个指针,然后要懂得找出环的起点的方法,其他变形的问题也就迎刃而解了。

  • 相关阅读:
    硬件加速器为人工智能应用服务
    js 获取指定字符串个数
    js 仿微信投诉—引入vue.js,拆分组件为单个js
    css 图片波浪效果
    svg path命令
    谷歌浏览器—打断点调试页面
    js 实现加载百分比效果
    js 实现纵向轮播
    css 图片高度自适应
    js 禁止/允许页面滚动
  • 原文地址:https://www.cnblogs.com/fengziwei/p/8137901.html
Copyright © 2020-2023  润新知