【爆刷力扣-链表】快慢指针

65 阅读3分钟

【leetcode 19】删除链表的倒数第N个结点

image.png

思路

1.定义fast指针和slow指针,初始值为虚拟头结点

image.png

2.fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:

image.png 3.fast和slow同时移动,直到fast指向末尾,如题:

image.png

4.删除slow指向的下一个节点

image.png

快指针走n+1步

代码

伪代码

dummyHead = new Node;
fast = dummyHead;
slow = dummyHead;
n++;
while(n-- && fast !=NULL){
    fast = fast ->next;
}
while(fast != NULL){
    fast = fast -> next;
    slow = slow -> next;
}
slow -> next = slow -> next -> next;
return dummyHead -> next;

代码

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        while(n-- && fast != NULL) {
            fast = fast->next;
        }
        fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
        while (fast != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next; 
        
        // ListNode *tmp = slow->next;  C++释放内存的逻辑
        // slow->next = tmp->next;
        // delete tmp;
        
        return dummyHead->next;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

【leetcode 142】环形链表

image.png

判断链表是否有环

原理:可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
解释:fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,这是毋庸置疑的。
通俗易懂:相当于套圈,一定会相遇 4649f5e30bdbb7c52ae2ad2eb308a08b_141.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.gif

如果有环,如何找到这个环的入口

假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。

image.png

速度 fast为2,slow为1
路程 slow=x+y          fast=x+y+n(y+z)
时间相等 列等式

image.png

意义从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点

也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。 让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。

0497ad94b32b0edc1f66c458f51a8bce_142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II%EF%BC%88%E6%B1%82%E5%85%A5%E5%8F%A3%EF%BC%89.gif

代码

伪代码

fast = head;
slow = head;
while(fast != NULL && fast ->next != NULL){
    fast = fast -> next -> next;
    slow = slow -> next;
    if(slow == fast){
        index1 = fast;
        index2 = head;
    }
    while(index1 != index2){
        index1 = index1 -> next;
        index2 = index2 -> next;
    }
    return index1;
}
return NULL;

代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {// 有环
                ListNode index1 = fast;
                ListNode index2 = head;
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}