代码训练营Day.4 | 24. 两两交换链表中的节点、19. 删除链表的倒数第N个节点、面试题 02.07. 链表相交、142. 环形链表II

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

1. LeetCode链接

https://leetcode.cn/problems/swap-nodes-in-pairs/submissions/489195706/

2. 题目描述

3. 想法

        先考虑头节点会不会变,此题明显会变,所以最好使用虚拟头节点。

        两两交换,涉及到三个节点要改变其next指针。

        

        pre、cur、post三个的next都要动。

        所以每次循环可以记录这三个指针。依次从后往前改变next指针。

        循环判断比较关键。例如,我就碰到这种错误

Line 20: Char 21: runtime error: member access within null pointer of type 'ListNode' (solution.cpp)

        原因在于我的判断为while(cur->next != NULL),忽略了cur本身有可能已经是NULL了。

/**
 * 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* cur = head;
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* pre = dummyHead;
        ListNode* post = head;
        while (cur != NULL && cur->next != NULL) {
            post = cur->next;
            cur->next = post->next;
            post->next = cur;
            pre->next = post;
            pre = cur;
            cur = cur->next;
        }
        head = dummyHead->next;
        delete dummyHead;
        return head;

    }
};

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

1. LeetCode链接

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/submissions/489197897/

2. 题目描述

3. 想法

        最后一个节点的前面第N-1个节点是要删除的,根据这个特点,只要设置两个指针,间隔距离N,当后面的指针到达最后,那么前面的指针所指的恰好是我们要删除的。

        这里的细节是,删除操作,最好是记录想删除节点的前一个,删起来更方便。

        我碰到如下错误。原因在于又没有考虑头节点是否会变。因为实际情况是头节点也有可能被删除,所以要搞个虚拟头节点。这么做既方便删除,也能找准head。

/**
 * 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* post = head;
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* cur = dummyHead;
        for (; n > 0; n--) post = post->next;
        while (post != NULL) {
            post = post->next;
            cur = cur->next;
        }
        ListNode* temp = cur->next;
        cur->next = temp->next;
        delete temp;
        head = dummyHead->next;    // 易忽略代码
        delete dummyHead;
        return head;

    }
};

面试题 02.07. 链表相交

1. LeetCode链接

https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/

2. 题目描述

3. 想法

        这个题目的特点为,两个链表尾端对齐,也就是说,如果有一长一短两个链表,长链表的长出部分必不可能是相交节点。而相同长度的链表,同时同步从head往后找,一定能找到相交节点。

        先求两个链表各自的长度,走完长链表的长出部分,然后再同时同步走即可。

        注意,是相同节点,而不是相同val值。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int i = 0, j = 0;
        ListNode* a = headA;
        ListNode* b = headB;
        while (a != NULL) {
            a = a->next;
            i++;
        }
        while (b != NULL) {
            b = b->next;
            j++;
        }
        if (i < j) {
            a = headB;
            b = headA;
        } else {
            a = headA;
            b = headB;
        }
        for (int n = abs(i - j); n > 0; n--) a = a->next;
        while (a != NULL) {
            if (a == b) return a;
            a = a->next;
            b = b->next;
        }
        return NULL;
    }
};

142. 环形链表

1. LeetCode链接

https://leetcode.cn/problems/linked-list-cycle-ii/

2. 题目描述

3. 想法

        纯数学,环追击问题。fast和slow。fast每次走两格,slow每次走一格。根据追及相遇时所用步数可以推断出很多东西。

        这里要注意是slow先动还是fast先动。slow先动写起来更简单。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head == NULL || head->next == NULL) return NULL;
        ListNode* fast = head;
        ListNode* slow = head;
        int i = 0;
        while (fast != NULL && fast->next != NULL) {
            if (i != 0 && slow == fast) break;
            i++;
            slow = slow->next;
            fast = fast->next->next;
        }
        if (fast == NULL || fast->next == NULL) return NULL;
        fast = head;
        while (fast != slow) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow;
    }
};

总结:

1. 先考虑是否需要dummyHead,比如head会变的情况下,需要。

2. 注意避免NULL->next。

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值