栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

链表六大解题套路(快慢双指针大法)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

链表六大解题套路(快慢双指针大法)

1、合并两个有序链表(leetcode 21 简单)
 

class Solution {
    public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* head = new ListNode(-1);
        ListNode* p = head;
        
        while(list1 && list2)
        {
            if(list1->val < list2->val)
            {
                p->next = list1;
                list1 = list1->next;
            }
            else{
                p->next = list2;
                list2 = list2->next;
            }
            
            p = p->next;
        } 
        
        p->next = list1 == nullptr ? list2 : list1;
        
        return head->next;
    }
};

2、合并K个升序链表(leetcode 23 困难)

技巧:使用优先队列,把链表节点放入一个最小堆,就可以每次获得k节点中的最小节点

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
       ListNode* head = new ListNode(-1);
       ListNode* p = head;

       while(list1 && list2)
       {
           if(list1->val < list2->val)
           {
               p->next = list1;
               list1 = list1->next;
           }
           else{
               p->next = list2;
               list2 = list2->next;
           }

           p = p->next;
       } 

       p->next = list1 == nullptr ? list2 : list1;

       return head->next;
    }
};

3、删除链表的倒数第 N 个结点(leetcode 19 中等)

技巧:使用快慢指针p1, p2,首先让p1先走k步,然后p2跟p1一起移动,直到p1走到最后一个节点,那么p2指向了倒k节点(要删除N节点,那么p2只要先走n+1步)

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
       ListNode* head = new ListNode(-1);
       ListNode* p = head;

       while(list1 && list2)
       {
           if(list1->val < list2->val)
           {
               p->next = list1;
               list1 = list1->next;
           }
           else{
               p->next = list2;
               list2 = list2->next;
           }

           p = p->next;
       } 

       p->next = list1 == nullptr ? list2 : list1;

       return head->next;
    }
};

4、链表的中间结点(leetcode 876 简单)

技巧:使用快慢节点low、fast,fast每次走两步,low每次走一步,当fast走到最后一个节点,那么low就是中间节点(注意:如果链表长度是偶数,low指向的右边那个节点)

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* low = head, *fast = head;

        while(fast && fast->next != nullptr)
        {
            low = low->next;
            fast = fast->next->next;
        }

        return low;
    }
};

5、判断是否环形链表(leetcode 141 简单)

技巧:使用快慢指针fast、low,fast每走两步,low走一步,如果快慢指针相遇(fast==low),那么就是有环;否则如果fast变为空指针,则无环

class Solution {
public:
    bool hasCycle(ListNode *head) {
       ListNode *low = head, *fast = head;

       while(fast && fast->next != nullptr)
       {
           low = low->next;
           fast = fast->next->next;

           if(low == fast)
                return true;//break; //有环
       } 

       return false;
    }
};

6、找出环形链表环的起点 II(leetcode 142 中等)

技巧:使用快慢指针fast、low,让fast每走两步,low走一步,如果快指针变成了空指针,那么无环;如果快慢指针相遇(fast == low),那么有环,此时让慢指针重新指向头结点(low=head),快慢指针一起往前走,下次相遇就是环的起点(如图解释):

如果有环,那么到达相遇点low指针走了k步,fast指针走了2k步,多走的部分在环内转圈圈(可得k步为圈大小的整数倍);假设环起点到相遇点为m步,那么相遇点到环起点就是k-m步,又因为head到环起点也是k-m步,所以快慢指针再走k-m步就会在环起点相遇

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
       ListNode *low = head, *fast = head;

       while(fast && fast->next != nullptr)
       {
           low = low->next;
           fast = fast->next->next;

           if(low == fast)
                break; //有环
       } 

       if(fast == nullptr || fast->next == nullptr)
       {
           return nullptr;
       }

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

       return low;
    }
};

7、 相交链表(leetcode 160 简单)

技巧1:使用hastmap记录第一链表的所有节点,让后遍历另一个链表,如果可以在hash中找到则表明他们相交

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
       unordered_map hashmap;

       ListNode* p = headA;
       while(p)
       {
            hashmap[p] = true;
            p = p->next;
       } 

       p = headB;
       while(p)
       {
           if(hashmap[p]){
               return p;
           }

           p = p->next;
       }

       return nullptr;
    }
};

进阶,技巧2:假设两个链L1,L2表相交,我们把L1独立部分长度设为len1, L2独立部分长度设为len2, 相交公共部分长度设为len3, 由于等式: len1 + len3 + len2 = len2 + len3 + len1 =>> L1长度(len1 + len3) + L2独立部分(len2) = L2长度(len2 + len3) + L1独立部分len1 ,那么只要使用两个指针p1,p2分别走完上面的路径(p1指向L1,如果遇到nullptr那么指向L2,p2指向L2,如果遇到nullptr那么指向L1),相遇的时候就是交点

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
       ListNode *p1 = headA, *p2 = headB;

       while(p1 != p2)
       {
            if(p1 == nullptr)
                p1 = headB;
            else
                p1 = p1->next;

            if(p2 == nullptr)
                p2 = headA;
            else
                p2 = p2->next;
       }

       return p1;
    }
};

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/743950.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号