Leetcode笔记-链表

102 阅读5分钟

反转链表

核心:想清楚反转的每一步迭代状态、目的,以及相对应的要点。

状态:当前节点的上一节点已反转,也就是pre指向了pre的上一节点,pre和curr之间没有连接,curr和curr.next正向连接。

目的:

  • 反转curr,指向pre,curr和curr.next无连接。
  • 继续迭代,即更新pre和curr。

要点:

  • 循环终止条件:由于每一步需要反转curr,而curr为空时无法反转,所以终止循环。
  • 先反转,再迭代,反转后没有节点指向curr.next,因此反转前需要注意保存节点curr。
  • 涉及和上一节点的交互,需要处理链表边界条件:dummy node。

反转链表II

在【反转链表】的基础上,关键是区分left、right、中间节点的不同反转方式。

如何只遍历一次?记录left及前序节点,right及后序节点,遍历完成后重新连接边界即可。

细节:

  • 一般都需要dummy node。
  • 需要修改节点交互关系的,一定注意保存临时节点。

K个一组翻转链表

在【反转链表II】的基础上,再加一层。整体思路简单,最外层循环遍历节点,每k个调用一次【反转链表II】,如果不满k个直接返回头节点。

细节:

  • 返回头节点时,永远返回dummy.next,尤其是在这种修改节点关系的题目中,修改后原head已经不再是head了。
  • 每次在k个节点内部完成反转,需要1)修改外部节点和start、end的连接关系。2)更新pre和curr便于下一次迭代,注意pre更新为新的end而非curr。

移除链表

基础题,做完【反转链表】再做这个,从整体思路是来说易如反掌。

但是,需要关注细节:

  • pre节点如何更新,取决于是否删除节点。
  • 一定要有dummy,最终返回结果一定要是dummy.next,以应对删除head的多种情况(后续是否有节点等)。

相交链表

第一时间应该想到哈希表:

  • 本质上是说哪个节点同时出现在了两个链表里。
  • 但这种解法没有利用链表结构。

更优解法:

  • 双链表,用双指针遍历。
  • 找出相交节点:如何让两个指针同时遍历到相交节点?链表相连。

合并两个有序链表

迭代思路:

  • 双链表,用双指针遍历。因为需要新链表,所以再加一个指针。
  • 新链表:dummy node起手,最终返回dummy.next即可。

递归思路:

  • 可以迭代求解时,都多考虑一步递归。未见得可行,未见得更优,纯思维训练。
  • 定义清楚状态即可,如果 l1 或者 l2 一开始就是空链表 ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。

分隔链表

核心:这道题和【K个一组翻转链表】类似,算法本身简单,关键是如何写出思路清晰、没有bug的代码。

思路:

  • 如何分隔?很简单,分成k组,n//k作为每组的基数,前n%k组的节点个数需要+1。
  • 如何实现?
    • 遍历一次链表,先计算出几个数字。
    • 二次遍历,产出列表。二次遍历,如何定义状态?
      • 直接的思路,是一层遍历,带着当前的group和group内部的数量,依次遍历每个节点。
      • 也可以压缩状态,两层遍历,状态更简洁。外层对group遍历,内层对group内部数量遍历。对复杂度没有影响。
  • 细节:
    • 由于返回的是节点的列表,即“分隔的”链表“片段”,每次产出一个片段,需要将尾节点的下一节点置空。
    • 凡是涉及置空,就需要引入tmp,储存节点。

环形链表

和【相交链表】类似,本质上是说有没有重复路过一个节点,因此首先考虑哈希表。

优化思路:同样参考【相交链表】,需要双指针。由于是同一链表,通过快慢指针构造双指针。

细节:

  • 快慢指针初始位置相同,while循环内先更新指针,再比较是否相等。
  • while循环条件:
    • 快指针在前,循环条件以快指针为准,即快指针不为空。
    • 快指针一次走两步,为了避免循环体内加判断,直接在while循环判定fast.next不为空。

环形链表II

在【环形链表】基础上,从定性(是否成环)变味了定量(返回入环节点)。

思路一,仍然采用哈希表,简单,返回第一个已拜访节点即可。

思路二,数学解,和【相交链表】思路类似,分段定义距离。

  • 环前a,入环相遇处b,环内剩余部分c。慢指针走了a+m*(b+c)+b,快指针走了a+n*(b+c)+b。
  • 同时,快指针速度是慢指针的两倍,即a+(n+1)b+nc = 2a+(2m+2)b+2mc,得到a=(n-2m-1)*(b+c) + c。
  • 环前部分,刚好等于从相遇处 出发,走X圈,回到入口的距离。
  • 因此,加入新指针,在快慢指针相遇时,与慢指针同步速出发。新指针与慢指针相遇位置,即为入环节点。

随机链表的复制

因为引入random指针,一次遍历无法解决问题。

  • 一次遍历,哈希表记录原节点-新节点映射关系。
  • 二次遍历,新节点赋值。