算法训练Day04|链表part02(LeetCode24. 两两交换链表中的节点、LeetCode19.删除链表的倒数第N个节点、LeetCode160.链表相交、LeetCode142.环形链表)

这里写目录标题

    • 24. 两两交换链表中的节点
      • 重点
      • 代码
    • 19.删除链表的倒数第N个节点
      • 重点
      • 代码
    • 160.链表相交
      • 重点
      • 代码
    • 142.环形链表II
      • 重点
      • 代码
    • 链表总结

文章讲解
视频讲解

24. 两两交换链表中的节点

题目链接

重点

  • 终止条件cur!=nullptr&&cur->next!=nullptr,cur!=nullptr是节点数是偶数,cur->next!=nullptr是节点数为奇数。
  • 注意节点指向的交换顺序,以下有两种思路。

代码

  • 自己的
    算法训练Day04|链表part02(LeetCode24. 两两交换链表中的节点、LeetCode19.删除链表的倒数第N个节点、LeetCode160.链表相交、LeetCode142.环形链表)_第1张图片
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyhead=new ListNode(0,head);
        ListNode* pre=dummyhead;
        ListNode* cur=head;
        while(cur!=nullptr&&cur->next!=nullptr){
            pre->next=pre->next->next;
            cur->next=pre->next->next;
            pre->next->next=cur;
            pre=pre->next->next;
            cur=pre->next;         
        }
        return dummyhead->next;
    }
};
  • 代码随想录
    这种方法需要cur指针的前后节点都要保存,不过代码可读性更高一些。
    算法训练Day04|链表part02(LeetCode24. 两两交换链表中的节点、LeetCode19.删除链表的倒数第N个节点、LeetCode160.链表相交、LeetCode142.环形链表)_第2张图片
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode* cur = dummyHead;
        while(cur->next != nullptr && cur->next->next != nullptr) {
            ListNode* tmp = cur->next; // 记录临时节点
            ListNode* tmp1 = cur->next->next->next; // 记录临时节点

            cur->next = cur->next->next;    // 步骤一
            cur->next->next = tmp;          // 步骤二
            cur->next->next->next = tmp1;   // 步骤三

            cur = cur->next->next; // cur移动两位,准备下一轮交换
        }
        return dummyHead->next;
    }
};

19.删除链表的倒数第N个节点

题目链接

重点

双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。实现起来不难。

代码

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead=new ListNode(0,head);
        ListNode* fast=dummyhead;
        ListNode* slow=dummyhead;
        while(n--){
            fast=fast->next;
        }
        while(fast->next!=nullptr){
            fast=fast->next;
            slow=slow->next;
        }
        ListNode* tmp=slow->next;
        slow->next=slow->next->next;
        delete tmp;
        return dummyhead->next;
    }
};

160.链表相交

题目链接

重点

  • 交点不是数值相等,而是指针完全相等。
  • 求出两链表的长度差,让curA移动到,和curB 末尾对齐的位置,如图,AB指针同时开始遍历,直到curA == curB,否则就没有交点。
  • 注意B链表比A链表长的情况。
    算法训练Day04|链表part02(LeetCode24. 两两交换链表中的节点、LeetCode19.删除链表的倒数第N个节点、LeetCode160.链表相交、LeetCode142.环形链表)_第3张图片

代码

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA=headA;
        ListNode* curB=headB;
        int lenghA=0;
        int lenghB=0;
        while(curA!=nullptr){
            curA=curA->next;
            lenghA++;
        }
        while(curB!=nullptr){
            curB=curB->next;
            lenghB++;
        }
        curA=headA;
        curB=headB;
        //让curA,lenghA都是最长链表的
        if(lenghA<lenghB){
            swap(lenghA,lenghB);
            swap(curA,curB);
        }
        int lenghsub=lenghA-lenghB;
        while(lenghsub--){
            curA=curA->next;
        }
        while(curA!=nullptr){
            curA=curA->next;
            curB=curB->next;
            if(curA==curB){
                return curA;
            }
        } 
        return NULL;         
    }
};

142.环形链表II

题目链接

重点

  • 怎么确定有没有环
    可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果有环,fast和slow一定会在环里相遇,即fast==slow。
    fast相对于slow是一个节点一个节点的靠近的,不会错过。

  • 怎么找环的入口
    算法训练Day04|链表part02(LeetCode24. 两两交换链表中的节点、LeetCode19.删除链表的倒数第N个节点、LeetCode160.链表相交、LeetCode142.环形链表)_第4张图片
    fast和slow相遇时,slow在环里一定没有走完一圈(slow进来时,fast在环里某个位置,如果slow走完了一圈,那fast就走了两圈)。即相遇时slow走的路程时x+y。
    相遇时,slow走了x+y,而fast指针走过x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针。因为fast速度是slow两倍,所以:
    (x + y) * 2 = x + y + n (y + z),
    整理公式之后为:x = (n - 1) (y + z) + z
    当 n为1的时候,公式就化解为 x = z,
    也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。
    n如果大于1,index1 指针在环里多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。

代码

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast=head;
        ListNode* slow=head;
        //while(fast->next!=NULL&&fast->next->next!=NULL)
        //这种会在空链表的情况下错
        while(fast != NULL && fast->next != NULL) {
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow){
                ListNode* index1=head;
                ListNode* index2=slow;
                while(index1!=index2){
                    index1=index1->next;
                    index2=index2->next;
                }
                return index1;
            }
        }
        return NULL;      
    }
};

链表总结

算法训练Day04|链表part02(LeetCode24. 两两交换链表中的节点、LeetCode19.删除链表的倒数第N个节点、LeetCode160.链表相交、LeetCode142.环形链表)_第5张图片

你可能感兴趣的:(算法,算法)