代码随想录算法训练营Day4|链表part02与总结

108 阅读4分钟

今日任务 

  • 24.两两交换链表中的节点 
  • 19.删除链表的倒数第N个节点 
  • 面试题 02.07. 链表相交 
  • 142.环形链表II 
  • 总结

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

题目链接:leetcode.cn/problems/sw…

文档讲解:programmercarl.com/0024.%E4%B8…

视频讲解:www.bilibili.com/video/BV1YT…

思路

两两交换,又要返回头节点,所以我们再次引入虚拟头节点

考虑修改一对节点的过程:第一个节点为curr

  1. 如果有curr且有curr.next才要修改
  2. 保存curr.next.next为tmp,方便下一轮修改
  3. curr.next.next = curr,把第二个节点指针反向
  4. prev.next = curr.next,让前一个节点的next指针指向第二个节点
  5. curr.next = tmp,把第一个节点指针指向第三个
  6. prev = curr; curr = tmp; 进入下一个循环

难点

如何确定每个next指针被修改的顺序?

链表里每个节点都要靠前序节点找到。所以保存一个修改一个,被用到最多的指针最后修改。 以及准备进入下一个循环时,对局部变量指针的修改顺序也很重要。

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

题目链接:leetcode.cn/problems/re…

文档讲解:programmercarl.com/0019.删除链表的倒…

视频讲解:www.bilibili.com/video/BV1vW…

思路

最容易想到的方法就是遍历一次链表,得到长度l,就可以计算出节点正数是第l-n个。再从头数一次删掉它 如何在一次遍历中实现呢? 考虑双指针,如果有一个快指针fast比慢指针slow快n个节点。那么当fast到达表尾的时候,slow就处在倒数第n个节点上。

由于被删掉的也可能是头节点,为了操作的一致性,引入虚拟头节点

为了方便操作,slow指针应该指向要删除节点的前序节点,那么fast最后应该停在链表的最后一个节点,即fast.next为空 故有如下步骤:

  1. 把fast,slow初始化为dummyhead
  2. fast向前走n步
  3. fast和slow同步向前移动,直至fast.next为空
  4. slow.next = slow.next.next
  5. 返回dummyhead.next

LeetCode 面试题 02.07. 链表相交

题目链接:leetcode.cn/problems/in…

文档讲解:programmercarl.com/%E9%9D%A2%E…

思路

假设两个链表的长度差为n。考虑两个指针A和B,如果两者间距离各自的head的长度之差也为n,一起向前移动,当两个指针第一次指向同一个节点时,这个节点就是链表的交点。 故有如下步骤:

  1. 分别遍历两个链表得到各自长度,计算出长度差n
  2. 让更长的链表指针从头走n步
  3. 检查指针是否重合或为空
    1. 两个指针同向前1步,继续检查
  4. 如果重合,返回当前节点
  5. 如果某指针为空,返回null(如果 listA 和 listB 没有交点,intersectVal 为 0

LeetCode 142 环形链表2️⃣

题目链接:leetcode.cn/problems/li…

文档讲解:programmercarl.com/0142.环形链表II…

思路

环形链表很容易想到快慢指针。考虑慢指针slow每次移动一个节点,快指针fast每次移动两个节点。两指针同时从head出发,如果两指针相遇,那一定有环;如果某指针变空,那么无环。 存在环的问题解决了,那怎么找到环的入口呢?

难点

FEE09380-A061-4968-B3E0-CFD1EA9926C7_4_5005_c.jpeg

不难看出slow和fast相遇的点一定在环上。对链表数据如上图假设,进行化简可以得到x+y=k(y+z)x+y=k(y+z) ,再变形可以得到x=(k1)(y+z)+zx=(k-1)(y+z)+z

即如果两个指针同时从head和汇合点出发,每次移动一节点,当从head出发的指针走出xx步,到达 交点时;从汇合点出发的指针也走过zz步加若干个环。而不论走过多少个环,在环上位置不变。所以第二个指针也在交点。

由此可以有如下步骤:

  1. fast和slow指针初始化为head
  2. 检查fast为空或fast.next为空(链表长度有奇有偶)
    1. fast走两步,slow走一步
    2. 如果fast和slow相等,退出循环
  3. 如果为空,返回-1
  4. 如果不为空,保存当前fast/slow为meet
  5. 初始化另一指针node为head
  6. 检查head和meet是否相等
    1. head和meet同时向前走一步
  7. 相等则返回node/meet

链表总结

链表.png

今日收获总结

今天学了四小时,部份双指针的题目都是有模糊的思路,却忘了怎么具体实现。实现起来也经常有细节错误,但比前两天好多了。熟能生巧~