文章链接:24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II、链表总结

视频链接:24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、142.环形链表II

题目链接:24. 两两交换链表中的节点 19.删除链表的倒数第N个节点面试题 02.07. 链表相交142.环形链表II

思路:

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

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_双指针

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0); // 虚拟头节点
        dummyHead->next = head;
        ListNode* cur = dummyHead;
        while(cur->next != NULL && cur->next->next != NULL){
            ListNode* temp1 = cur->next;
            ListNode* temp2 = cur->next->next->next;

            cur->next = cur->next->next; // 1
            cur->next->next = temp1; // 2
            cur->next->next->next = temp2; // 3

            cur = cur->next->next;
        }
        ListNode* result = dummyHead->next;
        delete dummyHead; // 记得释放内存
        return result;
    }
};

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

这道题的关键思路就是怎么找出倒数第n个节点。

首先让fast走n + 1,然后fast和slow一起向前走,直达fast指向NULL,这时slow指向倒数第n + 1个节点;那么slow->next 就是倒数第n个节点。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0); // 虚拟头节点
        dummyHead->next = head;
        ListNode* fast = dummyHead; // 快指针
        ListNode* slow = dummyHead; // 慢指针

        
        // 先让fast走n + 1;
        // 然后fast和slow一起向前走,直达fast指向NULL; 这时slow指向倒数第n + 1个节点;
        while(n-- && fast != NULL){
            fast = fast->next;
        }// fast走n步
        fast = fast->next;// fast走n + 1步

        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next; // 删除第n个节点

        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

面试题 02.07. 链表相交

思路为将A和B尾部对齐,然后从同一位置开始遍历,若curA等于curB,则为交点;若一直没有,则二者没有交点。

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_链表_02

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_快慢指针_03

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_链表_04

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;

        // 计算A的长度 
        while(curA != NULL){
            lenA++;
            curA = curA->next;
        }

        // 计算B的长度
        while(curB != NULL){
            lenB++;
            curB = curB->next;
        }
        curA = headA; // 要将操作指针重新放回头节点处
        curB = headB; 
        
        // 若B比A长,则要交换其长度和操作指针;即一定要保证A比B长
        if(lenA < lenB){
            swap(lenA, lenB);
            swap(curA, curB);
        }

        // 将A和B的尾部对齐:即curA和cueB一起前进并同时到达NULL
        int gap = lenA - lenB;
        while(gap--){
            curA = curA->next;
        }

        // 遍历A和B,直到找到交点
        while(curA != NULL){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }
};

142.环形链表II

这道题有两个难点,一是如何判断一个链表是否有环;二是如何找到环的入口。

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_快慢指针_05

如何判断一个链表是否有环

定义两个指针,分别为快慢指针,若两指针相遇就是有环。

如何找到环的入口

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_快慢指针_06

所以,由上图得,index1与index2相遇的地方就是环入口。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL){
            fast = fast->next->next;
            slow = slow->next;

            if(fast == slow){ // 判断一个链表是否有环
                ListNode* index1 = head;
                ListNode* index2 = fast;
                while(index1 != index2){ // 找环的入口
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }
        return NULL;
    }
};

困难:

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

问:为什么要用(两个)临时指针分别指向cur->next 和 cur->next->next->next ?


答:正如我在这道题的“思路”中画的图一样,cur->next = cur->next->next 该语句会将cur与cur->next之间的箭头断掉,如果不设立临时指针,那么等会需要用到的格子将没有办法可以找到。

问:为什么不能直接返回头节点?

答:头节点在执行完代码后已经改变了,而dummyHead->next才是真正改变后的头节点。

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

问:为什么删除第 n 个节点时,操作指针应该指向 n - 1 ?

答:因为删除第 n 个节点,就是把第 n - 1的节点的next指向第 n + 1 的节点,所以要将操作指针放在第 n - 1节点处。

问:怎么找到倒数第n个节点?

答:用双指针(快慢指针)。首先让fast走n + 1,然后fast和slow一起向前走,直达fast指向NULL,这时slow指向倒数第n + 1个节点;那么slow->next 就是倒数第n个节点。

面试题 02.07. 链表相交

142.环形链表II

问:为什么慢指针走不到一圈就被快指针追上?

答:因为慢指针走一圈,快指针肯定走了2圈,这两圈中肯定会遇到慢指针。

问:为什么只要判断fast != NULL 和 fast->next != NULL,不用判断fast->next->next != NULL ?

答:因为fast是走两步,若fast->next->next == NULL,那么走两步后fast就是原先的fast->next->next。

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_链表_07

今日收获:

今天用3小时的时间,写了有关链表的四道题,相比较昨天,对链表及其节点的相关操作更加熟悉了。