快慢指针-牛客题霸模板速刷(BM6、BM7、BM8、BM9、BM10)

快慢指针是指在链表或其他遍历对象中,通过两个相同方向的指针,即快指针和慢指针,以不同的速度遍历,从而实现寻找某个结点的目的。

BM6-判断链表中是否有环

题解:想象在环形跑道上两个运动员从同一起点出发以不同的速度向前奔跑,则到某一时刻两人一定会到达同一点。快慢指针同理,使快指针每次前移两个结点,慢指针每次前移一个结点,若链表中存在环,则之后快慢指针一定会指向同一结点。

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head == NULL)
            return false;
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL){
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow)
                return true;
        }
        return false;
    }
};

 

BM7-链表中环的入口结点

题解:使快慢指针以不同的速度前移,找到相遇的结点。而后让快指针指向头结点,让两个指针以相同的速度前移,两指针相遇的结点即为链表中环的入口结点。

class Solution {
  public:
    ListNode* hasCycle(ListNode* head) { 
        if (head == NULL)
            return NULL;
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != NULL && fast->next != NULL) { 
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow)
                return slow;
        }
        return NULL;
    }
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        ListNode* slow = hasCycle(pHead);
        if (slow == NULL)
            return NULL;
        ListNode* fast = pHead;
        while (fast != slow) {
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

 

BM8-链表中倒数最后k个结点

题解:开始时快慢指针同时指向头结点,先让快指针向前移动k个结点,再让慢指针和快指针以同样的速度前移,当快指针到达链表尾端时,慢指针前移了n-k个结点,即指向了链表中倒数第k个结点

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pHead, int k) {
        ListNode* fast = pHead;
        ListNode* slow = pHead;
        for(int i = 0; i < k; i++){
            if(fast != NULL)
                fast = fast->next;
            else
                return slow = NULL;
        }
        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

 BM9-删除链表的倒数第n个结点

题解:与BM8类似。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) { 
        ListNode* res = new ListNode(-1);
        res->next = head;
        
        ListNode* cur = head;
        ListNode* fast = head;
        ListNode* pre = res;

        while(n--)
            fast = fast->next;
        while(fast != NULL){
            fast = fast->next;
            pre = cur;
            cur = cur->next;
        }
        pre->next = cur->next;
        return res->next;
    }
};

 

BM10-两个链表的第一个公共结点

题解:因为两个链表的长度可能不同,所以可以让快慢指针分别遍历一遍长短链表,则最终在公共结点处一定会相遇。假设链表1长度为n,链表2长度为m(n > m),快指针遍历链表1,慢指针遍历链表2,当两指针各到达链表尾端时,再回头遍历另一个链表,最终在公共结点处相遇。

 

#include <list>
class Solution {
public:
    int listLength(ListNode* pHead){
        ListNode* p = pHead;
        int n = 0;
        while(p != NULL){
            p = p->next;
            n++;
        }
        return n;
    }
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        int p1 = listLength(pHead1);
        int p2 = listLength(pHead2);
        int n = 0;
        if(p1 > p2){
            n = p1 - p2;
            while(n--)
                pHead1 = pHead1->next;
        }else{
            n = p2 - p1;
            while(n--)
                pHead2 = pHead2->next;
        }
        while(pHead1 && pHead2 &&(pHead1 != pHead2)){
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
        }
        return pHead1;
    }
};

 

posted @ 2023-01-29 11:55  努力向上的派大星  阅读(133)  评论(0编辑  收藏  举报