代码随想录Day4: 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

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

题目链接/文章讲解/视频讲解: 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

  • 设置虚拟头节点
  • 每次需要交换两个点,所以需要next和next->next 都存在
  • cur从dummynode开始
  • 设置两个临时指针
  • 0->2
  • 1->3
  • 2->1
  • cur后移两位
ListNode* swapPairs(ListNode* head) {
       ListNode* dummynode = new ListNode(0);
       dummynode->next = head;
       ListNode* cur = dummynode;
       while(cur->next!=nullptr&&cur->next->next!=nullptr){
           ListNode* tmp = cur->next;
           ListNode* tmp2 = cur->next->next;

           cur->next = tmp2;
           tmp->next = tmp2->next;
           tmp2->next = tmp;
           

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

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

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

双指针,fast先走n+1步,slow再走,这样fast遍历完时slow走到倒数n-1个节点,此时将slow的next指针调整到next->next

ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummynode = new ListNode(0);
        dummynode->next = head;
        ListNode* fast = dummynode;
        ListNode* slow = dummynode;
        while(n--&&fast!=nullptr){
            fast = fast->next;
        }
        fast = fast->next;
        while(fast!=nullptr){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next; 
        return dummynode->next;
    }

面试题 02.07. 链表相交

题目链接/文章讲解: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

第一次遍历,记录两个表长及表长差,将更长的表指针先移动表长差位,之后一同移动,如果两个相同,则是相交处,如果遍历完没有相同,则不相交

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int la = 0,lb = 0,distance;
        while(curA != nullptr){
            curA = curA->next;
            la++;
        }
        while(curB != nullptr){
            curB = curB->next;
            lb++;
        }

        curA = headA;
        curB = headB;
        
        if(lb>la){
            swap(la,lb);
            swap(curA,curB);
        }
        distance = la-lb;

        while(distance--){
            curA = curA->next;
        }
        while(curA!=nullptr){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }

142.环形链表II

题目链接/文章讲解/视频讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html

判断是否有环

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

怎样找到环的起始点

设链表共有 a+ba+ba+b 个节点,其中 链表头部到链表入口 有 aaa 个节点(不计链表入口节点), 链表环 有 bbb 个节点(这里需要注意,aaa 和 bbb 是未知数,例如图解上链表 a=4a=4a=4 , b=5b=5b=5);设两指针分别走了 fff,sss 步,则有:

fast 走的步数是 slow 步数的 222 倍,即 f=2sf = 2sf=2s;(解析: fast 每轮走 222 步) fast 比
slow 多走了 nnn 个环的长度,即 f=s+nbf = s + nbf=s+nb;( 解析: 双指针都走过 aaa
步,然后在环内绕圈直到重合,重合时 fast 比 slow 多走 环的长度整数倍 )。 将以上两式相减得到 f=2nbf =
2nbf=2nb,s=nbs = nbs=nb,即 fast 和 slow 指针分别走了 2n2n2n,nnn 个环的周长。

接下来该怎么做呢?

如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nbk=a+nbk=a+nb ,即先走 aaa
步到入口节点,之后每绕 111 圈环( bbb 步)都会再次到入口节点。而目前 slow 指针走了 nbnbnb 步。因此,我们只要想办法让
slow 再走 aaa 步停下来,就可以到环的入口。

但是我们不知道 aaa 的值,该怎么办?依然是使用双指针法。考虑构建一个指针,此指针需要有以下性质:此指针和 slow 一起向前走 a
步后,两者在入口节点重合。那么从哪里走到入口节点需要 aaa 步?答案是链表头节点head

作者:Krahets 链接:https://leetcode.cn/problems/linked-list-cycle-ii/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

ListNode *detectCycle(ListNode *head) {

        ListNode *fast = head;
        ListNode *slow = head;

        while(fast!=nullptr&&slow!=nullptr&&fast->next!=nullptr){
            fast = fast->next->next;
            slow = slow->next;
            if(slow == fast){
                fast = head;
                while(slow != fast){
                    fast = fast->next;
                    slow = slow->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值