首页 > 编程语言 >代码随想录算法训练营第四天LeetCode24,19,02

代码随想录算法训练营第四天LeetCode24,19,02

时间:2023-01-01 23:56:33浏览次数:67  
标签:02 ListNode 19 随想录 next 链表 ptr 节点 指针

代码随想录算法训练营第四天|LeetCode24,19,02.07,142

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

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/description/
//采用虚拟头节点
/**
 * 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 *virtualHead = new ListNode();
        virtualHead->next = head;
        //保存要进行交换的节点
        ListNode *pre = virtualHead;
        ListNode *ptr = head;
        ListNode *tmp;
        while(ptr && ptr->next != NULL){
            tmp = ptr->next;
            ptr->next = tmp->next;
            tmp->next = ptr;
            pre->next = tmp;
            pre = ptr;
            ptr = ptr->next;

        }
        return virtualHead->next;

    }
};

![image-20230101205534043](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101205534043.png)

要点:分清pre ,tmp,ptr指针指向的节点

视频讲解链接:https://www.bilibili.com/video/BV1YT411g7br/?spm_id_from=333.788&vd_source=8d6cce160628d93add1e5fa9299f622d
文章讲解链接:https://programmercarl.com/0024.两两交换链表中的节点.html

LeetCode 19 删除链表的倒数第 N 个结点

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/
//版本一:先计算链表长度,算出删除元素的正数位置,再遍历整个链表
/**
 * 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 *virtualHead = new ListNode();
        virtualHead->next = head;
        //确定该链表的长度
        ListNode *ptr = virtualHead;
        int size = 0;
        while(ptr->next != NULL){
            ptr = ptr->next;
            size++;
        }
        //遍历该链表
        ListNode *ptr1 = virtualHead;
        ListNode *ptr2 = head;
        //计算是正数第几个节点
        int index = size - n + 1;
        //记录要删除的节点
        ListNode *tmp;
        while(--index){
            ptr1 = ptr1->next;
            ptr2 = ptr2->next;
        }
        tmp = ptr2;
        ptr1->next = ptr2->next;
        delete tmp;
        
        return virtualHead->next;
        
    }
};
视频讲解链接:https://www.bilibili.com/video/BV1vW4y1U7Gf/?spm_id_from=333.788&vd_source=8d6cce160628d93add1e5fa9299f622d
文章讲解链接:https://programmercarl.com/0019.删除链表的倒数第N个节点.html

根据视频和文章讲解做出如下总结:

1.设置虚拟头节点,方便处理实际删除的节点。

2.定义fast和slow指针,初始值为虚拟头节点。

![image-20230101210458271](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101210458271.png)

3.fast首先走n+1步,是为了让slow指向要删除节点的前一个节点。

![image-20230101210631896](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101210631896.png)

4.fast和slow同步走,直到fast走到末尾NULL处。

![image-20230101210706528](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101210706528.png)

5.删除slow指向的后一个节点。

![image-20230101210744612](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101210744612.png)

//版本二:使用快慢指针,一次遍历就可以删除掉元素
/**
 * 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 *virtualHead = new ListNode();
        virtualHead->next = head;
        //此处不使用遍历链表确认长度的方式,使用快慢双指针
        ListNode *slowptr = virtualHead;
        ListNode *fastptr = virtualHead;
        //让快指针比慢指针快 n+1 步,这样慢指针正好能指向删除结点的前一个位置
        n = n + 1;
        while(n-- && fastptr != NULL){
            fastptr = fastptr->next;
        }
        //快慢指针同时移动,直到快指针指向NULL值
        while(fastptr != NULL){
            slowptr = slowptr->next;
            fastptr = fastptr->next;
        }
        //删除节点
        ListNode *tmp = slowptr->next;
        slowptr->next = tmp->next;
        delete tmp;
        

        return virtualHead->next;
        
    }
};

LeetCode 面试题 02.07. 链表相交

题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/
//通过将A和B链表对齐的方式,遍历比较,代码基本一次过
/**
 * 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 size1 = 0, size2 = 0;
        //确定A链表的长度
        ListNode *ptr = headA;
        while(ptr != NULL){
            ptr = ptr->next;
            size1++;
        }
        //确定B链表的长度
        ptr = headB;
        while(ptr != NULL){
            ptr = ptr->next;
            size2++;
        }
        //将A链表与B链表对齐
        ListNode *ptr1 = headA;
        ListNode *ptr2 = headB;
        //让ptr1成为最长链表的表头
        if(size1 < size2){
            swap(size1, size2);
            swap(ptr1, ptr2);
        }
        //求A和B的长度差
        int len = size1 - size2;
        //使ptr1和ptr2对齐
        while(len--) ptr1 = ptr1->next;
        //遍历A和B链表,依次做比较
        while(ptr1 != NULL){
            if(ptr1 == ptr2){
                return ptr1;
            }
            ptr1 = ptr1->next;
            ptr2 = ptr2->next;
        }
        return NULL;

    }
};
文章讲解链接:https://programmercarl.com/面试题02.07.链表相交.html

LeetCode 142 环形链表 II

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/
//完全失败的代码,竟然使用了双重循环来找环形,快慢指针没想到真是不应该!
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
ListNode *detectCycle(ListNode *head) {
        //使用双重循环会超出时间限制
        //pos不作为参数传递,说明节点的数据成员不包括pos
        //先用双重循环试试
        ListNode *ptr1 = head;
        ListNode *ptr2 = head->next;
        //带环的链表貌似算不出链表长度 
        for(;ptr1 != NULL; ptr1 = ptr1->next){
            for(; ptr2 != NULL; ptr2 = ptr2->next){
                if(ptr2 == ptr1){
                    return ptr1;
                }
            }
        }
        return NULL;
}
视频讲解链接:https://www.bilibili.com/video/BV1if4y1d7ob/?spm_id_from=333.788&vd_source=8d6cce160628d93add1e5fa9299f622d
文章讲解链接:https://programmercarl.com/0142.环形链表II.html

本题非常值得记录,里面蕴含的有关数学不等式的思想非常有趣。

根据视频和文章讲解链接做出如下总结:

1.判断链表是否有环,可以使用快慢指针法,分别定义快指针和慢指针,从头节点出发,快指针每次走两步,慢指针每次走一步。这时候可能有疑问,为什么快指针会追上慢指针呢?而不是快指针和慢指针永远错开呢?首先,fast指针一定先进入环中,如果fast指针和slow指针相遇,那一定是在环中相遇。 其次,对于环来说,可以画一个环,让环中的fast指针在任何一个节点追逐slow指针,因为fast是走两步的,slow是走一步的,在环中fast相当于以相对快slow一步的速度来追赶slow。可以假设slow静止不动,fast以一次一步的速度来追赶,所以一定能追得上。

2.如果有环,如何找到环的入口位置?假设头节点到环的入口的节点数为x,环入口到快慢指针相遇的节点的节点数为y,从相遇节点到环入口节点位置的节点数为z。

![image-20230101224352087](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101224352087.png)

3.根据上图,可以知道,相遇时slow指针走了x+y的距离,fast指针走了x + n(y + z) + y,n为fast指针在环中转了n圈才遇到slow指针。
$$
fast = 2节点/步; slow = 1节点/步;
$$

$$
2(x + y) = x + n * (y+z)+y;
$$

$$
x+y = n*(y+z);
$$

$$
x=n*(y+z)-y;
$$

$$
x=(n-1)(y+z)+z;n>=1
$$

4.由上面的公式可以看出,当 n = 1时,x = z。这就意味着,从头节点出发一个节点,和相遇节点出发一个节点,这两个指针每次只走一个节点,那么两个节点相遇的节点位置就是环形的入口位置。

5.验证是否有环设置fastptr和slowptr指针;找到环入口设置index1和index2指针

6.tips补充:在慢指针移动过程中,为什么最后走得距离是 x+y 而不是 x + k*(y+z) + y呢?也就是为什么slow指针在环中只用走不到一圈就会被fast指针追上?首先,slow指针进环中时,fast指针已经进环,此时可以将环铺开成若干条线(因为可以循环无数次)。

![image-20230101233240833](/Users/siyiwang/Library/Application Support/typora-user-images/image-20230101233240833.png)
$$
当slow走完一圈时,fast一定走在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) {
        //重新想办法 理解寻找环和找到环入口
        //看了视频讲解,很牛逼的办法值得记录
        //设置快慢指针,确定相遇的位置
        ListNode *slowptr = head;
        ListNode *fastptr = head;
        //设置两个指针,确定环入口的位置
        ListNode *index1, *index2;
        //fastptr一次走两个节点,slowptr一次走一个节点
        while(fastptr != NULL && fastptr->next != NULL){
            fastptr = fastptr->next->next;
            slowptr = slowptr->next;
            if(fastptr == slowptr){ //说明相遇,有环
                //现在确认环的入口
                index1 = head;
                index2 = fastptr;
                while(index1 != index2){
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
            
        }
        return NULL;


    }
};

标签:02,ListNode,19,随想录,next,链表,ptr,节点,指针
From: https://www.cnblogs.com/shadowbringer/p/17019283.html

相关文章

  • 2022-12月读书整理
    12月读书整理:12.10认识自己,选择生活唯一不变的是改变本身。Theonlythingthatdoesn'tchangeischangeitself.12.11精要主义试图做所有“正确”的事情,追求尽善......
  • 19、前端基础-ES6---异步编排
    ......
  • 从微信读书聊起2023
    去年整整一年,我花了大量时间在微信读书上看各种电子书。收藏了900多本,真正完整读完的只有22本。平均下来一个月不到2本,但是看完的的确都是各种细分领域的经典,收获颇多。我......
  • 刷刷刷Day4|面试题 02.07. 链表相交
    面试题02.07.链表相交LeetCode题目要求给你两个单链表的头节点 headA和headB,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回null。图示两......
  • 2023新年第一篇随笔(聊聊基金理财)
    2023年1月1日,是新年的第一天,祝大家新年快乐!今天突然想写点东西,就主要围绕去年刚接触的基金谈起吧,2022年4月9号,我在B站无意中发现up遇见狂神说(up是我大学生活中......
  • 名人名言_2023
    日常学习名人名言,激励自己......
  • 2023,元旦快乐!
    今天是2023年的第一天,也是元旦节日,又是元气满满的一天,中午爸爸妈妈做了一大桌子菜,十分可口。他们工作十分辛苦,希望在新的一年里,爸爸妈妈以及各位亲友们身体健健康康,生活幸福......
  • .NET周报【12月第4期 2022-12-31】
    祝大家新年快乐!国内文章『再看.NET7』数值类型https://mp.weixin.qq.com/s/ctiBMPY6Hditk81AzHSRng在C#中,有int16,用short来定义;有int32,用int定义;用int64,用long来定义......
  • 云锵投资 2022 年收益统计及 12 月简报
    本月是本年度最后一月,对本年的各策略进行了年度的收益统计:2022年12月云锵投资团队月报:摘要本月量化基金策略业绩:中;本月量化股票策略业绩:中;(优良中差,表明全国排名......
  • Hello 2023!
        2022年过去了,人生进入了第三轮。原本不太想写博客的,一来觉得非技术的博客放出来给别人看,多少有点矫情的意味;二来,我确实没什么写日记的习惯,过去的二十多年也没......