代码随想录训练营day4 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 160. 链表相交 142.环形链表II

84 阅读3分钟

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

题目链接:leetcode.cn/problems/sw…

要点

  • 注意:交换两个节点的顺序需要先将cur指向前一个节点,再通过三次修改指针,完成一对的交换
  • cur = cur->next->next 再去对调下一对节点

O(n)写法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(-1, head);
        ListNode* cur = dummyHead;

        while (cur->next != nullptr && cur->next->next != nullptr) {
            //由于在修改指针的过程中,会丢失指向,预先记录
            ListNode* one = cur->next;
            ListNode* three = cur->next->next->next;

            //依次改指向
            cur->next = cur->next->next;
            cur->next->next = one;
            one->next = three;

            cur = cur->next->next;
        }
        return dummyHead->next;
    }
};

总结

两两对调节点,按顺序操作修改指针,丢失的1号位、3号位节点就事先记录一下。

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

题目链接:leetcode.cn/problems/re…

要点

  • fast指针指向NULL时,slow应指在待删节点的前一个,所以fast多走一步

双指针法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(-1, head);
        ListNode* fast = dummyHead;
        ListNode* slow = dummyHead;

        while (n--) {
            fast = fast->next;
        }
        //fast多走一步
        fast = fast->next;
        while (fast != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* tmp = slow->next;
        slow->next = slow->next->next;
        delete tmp;
        return dummyHead->next;
    }
};

总结

双指针法,也是快慢指针的一题,思路还是很朴实无华的

160. 链表相交

题目链接:leetcode.cn/problems/in…

要点

  • 将两链表右对齐后,长的链表cur指针和短的cur指针对齐,从此节点开始比对是否是同一节点
  • 注意bug:没有int a, b = 0; 这种初始化方法

右对齐法

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while (curA != NULL) {
            curA = curA->next;
            lenA++;
        }
        while (curB != NULL) {
            curB = curB->next;
            lenB++;
        }

        if(lenA < lenB) {
            int tmp = lenB;
            lenB = lenA;
            lenA = tmp;
            curB = headA;
            curA = headB;
        }else{
            curA = headA;
            curB = headB;
        }

        int gap = lenA - lenB;
        while (gap--) {
            curA = curA->next;
        }
        while (curA != NULL) {
            if (curA == curB) {return curA;}
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }
};

总结

就按右对齐的思路按部就班写,默认A链表为长的,要交换一下规范接下来的代码

还是要多写,写就能发现很多细小的bug

142.环形链表II

题目链接:leetcode.cn/problems/li…

要点

  • fast每次走两步,slow走一步,如果有环一定相遇在环内
  • 相遇的话,slow一定在第一圈环内被追上

1.PNG

  • 由推导得,x = z + k(z + y) ,当两指针分别从相遇点和head,同时一步步走,必会相遇在入圈点处(k为自然数)
  • fast指针只要自身和fast->next非空,就不会出现空指针异常

由分析得

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;
    }
};

总结

这题主要是x = z的关系重要,有思路代码很好写