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

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

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
文章讲解:https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
视频讲解:https://www.bilibili.com/video/BV1YT411g7br
状态:做了出来

思路

自己看到题目的第一想法:
先单独谈论空节点和一个节点的情况,然后就可以讨论循环中连续两个和连续三个的情况
看完随想录之后的想法:
大题思想是一样的,不过这里是从虚拟头节点出发为cur,我自己是把虚拟头节点当成了pre开始出发,二者比较起来的差异就是我自己写的时候,我是从头节点开始跳的,1-3-。。。而代码随想录是从0开始跳的,0-2-4,这样做的好处是本身奇数的时候就不用排最后两个,因此代码更简答

代码实现

①虚拟头节点当pre,从头节点开始跳

/**
 * 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_head = new ListNode(0);
        dummy_head -> next = head;
        ListNode* cur = head;
        ListNode* pre = dummy_head;
        if(head == NULL || head -> next == NULL){
            return head;
        }else{
            ListNode* new_head = head -> next;
            while(cur -> next != NULL){
                if(cur -> next -> next != NULL){
                    ListNode* tmp = cur -> next -> next;
                    cur -> next -> next = cur;
                    pre -> next = cur -> next;
                    cur -> next = tmp;
                    pre = cur;
                    cur = cur -> next; 
                }else{
                    cur -> next -> next = cur;
                    pre -> next = cur -> next;
                    cur -> next = NULL;
                }
            }
            return new_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* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode(0);
        dummy_head -> next = head;
        ListNode* cur = dummy_head;
        while(cur -> next != NULL && cur -> next -> next != NULL){
            ListNode* tmp = cur -> next -> next -> next;;
            
            cur -> next -> next -> next = cur -> next;
            cur -> next = cur -> next -> next;
            cur -> next -> next -> next = tmp;
            
            cur = cur -> next -> next;
        }
        return dummy_head -> next;
    }
};

今天时间分配不好,补了昨天的,今天的就做出一道,明天再补了

============================================

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

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
文章讲解:https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html
视频讲解:https://www.bilibili.com/video/BV1vW4y1U7Gf
状态:用比较笨的方法写了出来

思路

自己看到题目的第一想法:
用之前写过设计链表中查找索引元素的方法,去找到倒数第N+1个元素,然后去删除
看过代码随想录之后的想法:
可以设置两个指针,快指针和慢指针。先让快指针比慢指针先走n步,然后再快慢指针一起走,到最后快指针为空指针时,此时慢指针就是我们要删除的节点,我们删除节点时一般看前一个节点,因此快指针需要先走n+1步。

代码实现

/**
 * 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_head = new ListNode(0);
        dummy_head -> next = head;
        ListNode* fast = dummy_head;
        ListNode* slow = dummy_head;
        n++;
        while(n --){
            fast =  fast -> next;
        }
        while(fast != NULL){
            fast = fast -> next;
            slow = slow -> next;
        }
        slow -> next = slow -> next -> next;
        return dummy_head -> next;
    }
};

面试题02.07.链表相交

题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
文章讲解:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html
状态:做了出来

思路

利用上一题删除倒数第N个元素的思想,两个链表若有交叉点,则结尾后一段一定是相等的,因此我们可以让长度长的链表先走,让两个链表末位对齐,然后就是同步走,直至找到节点相等的位置
代码随想录里有个思想可以借鉴,就是为了少一次重复的循环,可以一直让A链表保持最长,若不是最长,则swap(headA,headB)

代码实现

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while (curA != NULL) { // 求链表A的长度
            lenA++;
            curA = curA->next;
        }
        while (curB != NULL) { // 求链表B的长度
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            swap (lenA, lenB);
            swap (curA, curB);
        }
        // 求长度差
        int gap = lenA - lenB;
        // 让curA和curB在同一起点上(末尾位置对齐)
        while (gap--) {
            curA = curA->next;
        }
        // 遍历curA 和 curB,遇到相同则直接返回
        while (curA != NULL) {
            if (curA == curB) {
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }
};

环形链表Ⅱ

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
文章讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
视频讲解:https://www.bilibili.com/video/BV1if4y1d7ob
状态:不会

思路

首先,我们考虑如何找到环,当设置一个快指针步长为2,慢指针步长为1,若有环,则它们终会相遇。
如何去找寻入口呢?
在这里插入图片描述
可定义slow:x+y,fast:x+y+n(y+z),由于fast是slow速度的二倍,则2(x+y)=x+y+n(y+z)
化简得x=z+(n-1)(y+z),可知x为z+走了n-1圈,因此找入口时,注意一下,一个从起始点出发,一个从相遇点出发,而这一定能够同时到达环形入口处。
我们解答一下为什么一圈就追了
在这里插入图片描述

代码实现

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

收获

首先链表里面也经常用双指针,pre和cur指针以及快慢指针,
在间隔跳转的时候,考虑从虚拟头节点还是头节点开始跳
环形相关的知识

链表的总结
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值