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

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

题目链接/文章讲解/视频讲解: 代码随想录

/**
 * 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* dummy = new ListNode(-1);
        dummy->next = head;
        ListNode* prevNode = dummy;
        while ((head != nullptr) && (head->next != nullptr)){
            ListNode* firstNode = head;
            ListNode* secondNode = head->next;
            firstNode->next = secondNode->next;
            secondNode->next = firstNode;
            prevNode->next = secondNode;
            prevNode = firstNode;
            head = firstNode->next;
        }
        ListNode* result = dummy->next;
        delete dummy;
        return result;
    }
};

做法和随想录有点不一样 用了 prev, 少用一个temp。

又是容易绕进去的一题,一次对了也还不能保证下次也对,三刷预定了

19.删除链表的倒数第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* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode();
        ListNode* curr = head;
        ListNode* fast = head; 
        dummy->next = head;
        ListNode* prev = dummy;
        for (int i = 0; i < n; i++){ 
            fast = fast -> next;
        }
        while (fast != nullptr) {
            prev = prev -> next;
            curr = curr -> next;
            fast = fast -> next;
        }   
        prev->next = curr->next; 
        delete curr; 
        head = dummy->next;
        delete dummy;
        return head;
    }
};

return 的时候忘记了重置head为dummy->next, 导致报了个heap-use-after-free on address的错,大概是删除了head但又试图return head导致的。

判断fast提前走几步时脑子转不动,所以举一个只有一个node的例子来决定走几步

面试题 02.07. 链表相交

本题没有视频讲解,大家注意 数值相同,不代表指针相同。

题目链接/文章讲解:代码随想录

同时似乎也是leetcode 160

忘记怎么解了,看到题的思路是先找终止点沿路count,然后决定谁先走几步,一一对比。但印象中好像有更好的解法,决定先看文章讲解。

检索了一番 没有一遍过的解法,除开一个一路走一路加标记的解法,但这改变了链表结构。

two pointer的解法是我印象中更加巧妙的一个,但实际上也需要走两遍,所以这次还是练习代码随想录里的count解法,虽然行数多些,但有一种朴实暴力的美。

/**
 * 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 count = 0; 
        ListNode *currA = headA;
        ListNode* currB = headB;
        while (currA != nullptr && currB!= nullptr){
            currA = currA->next;
            currB = currB->next;
        }
        while (currA != nullptr){
            currA = currA->next;
            count++;
        }
        while (currB!= nullptr){ 
            currB = currB->next;
            count--;
        }
        currA = headA;
        currB = headB;
        while (count > 0){
            currA = currA->next;
            count--;
        }
        while (count < 0){
            currB = currB->next;
            count++;
        }
        while (currA != nullptr && currB!= nullptr){
            if (currA == currB){
                return currA;
            }
            currA = currA->next;
            currB = currB->next;
        }
        return NULL;
    }
};

没意识到可以用自带的swap来省两行,但看上去还怪对称的 先不管了。下一刷应该还是会用two pointer, 因为写起来能短一点。

142.环形链表II

算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。

题目链接/文章讲解/视频讲解:代码随想录

这个快慢指针印象很深刻,但只记得怎么找环,记不清楚怎么找环入口了。

面试要是也这样就先用哈希表吧。

挣扎一下式子总结理清思绪:

慢指针步数(x+y), x为起点到环入口,y为环里距离

快指针步数 2(x+y),因为快指针快一倍

2 (x + y) - ab = x + y (快慢指针相交时,快的多走了a圈,一圈为b)

那么x+y = ab(一般我就卡在这里,但这样就肯定不行,需要再分解现状)

b拆成(y+z),入口到相遇点的距离和剩余距离组成一圈

那么x+y = a(y+z)

代码随想录进行了因式分解 x = (a-1)(y + z) +z

y + z 是一圈的距离

这是我第二个容易卡壳的地方,之前总是想不清楚 这个式子的(a-1)如何能对上号。通过分析我意识到 可以举出例子:一个指针在快慢交点,一个指针在起点开始等速走的时候,什么时候会有很多圈? 那应当就是 环小,x很长的时候。这个时候环内指针要多走很多圈才可以和起点开始的指针相遇,那就是(a-1)圈。

所以如果一个指针在交点,一个指针在起点开始等速走,交点指针走 z + (a - 1) 圈 步 等于 起点指针走x步 而环入口的定义便是 起点开始的第x个node。

/**
 * 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) {
        ListNode* slow = head;
        ListNode* fast = head; 
        while (fast != NULL && fast->next != NULL){
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow){ 
                break;
            }
        }
        if (!fast || !fast->next){
            return NULL;
        } 
        slow = head;
        while(fast != slow){
            fast = fast->next;
            slow = slow->next;
        }
        return fast;  
    }
};

总结



今日学习3小时,感到至少不再害怕写c++了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值