算法笔记-链表
See code in Git Repository/Leetcode-algorithm/data_structure/Linked_list
Most in Link_List_Review.py
链表的环
判断是否有环:
- 维护快慢两个指针, 快指针一次前进两位,慢指针一次一位。 若两个指针能够相遇,则有环。 若快指针运动到末尾还未与满指针相遇则无环。
- 注意, 如果有环,则使用 while node.next is not None为判断条件时,一定会有快慢指针相遇的时候, 因为如果有环的话, 那么链表就没有尾节点,也就是没有next为None的节点。换句话说, 如果链表有尾节点,也就是next 为none的节点,那么链表一定无环。
More in Detail update at 16/04/2023
1 | while (fast != null && fast.next != null) { |
快慢指针同向奔跑, fast 的速度是slow的一倍, 如果有环, 那么两者必定在某一点相遇, 也即fast会追上slow, 此时fast正好比slow多走了一圈的路程。
找到链表环的入口:
- 首先使用上述方法判断是否有环
- 找到环中任意一个节点。
- 方法: 若有环, 则使用上述方法判断过程中会得到两个指针相遇的节点。
- 当快慢指针相遇时,创建一新指针从头节点出发, 当该新指针与慢指针相遇时所处的结点即为环的入口。
More in Detail update at 16/04/2023
1 | // 若链表无环, 则fast会走到链表结尾, 而此时slow还在链表中间。 |
Explaination
slow 路程 = x + y; fast 路程 = x + y + n(y + z)
由于 fast = 2 slow:
2(x+y) = x+y + n (y+z);
x + y = n (y + z)
x = (n-1) y + nz
其中n为fast在环中跑的圈数。在相遇时, fast指针最少在环中已经跑了一圈, 所以 n >=1。
假设 n = 1, 则得 x=z, 也即当slow&fast相遇以后, 使得slow在head开始跑, fast在meeting point开始跑, 则两者必定在entry poin相遇。
相交链表
使pA, pB两个指针分别从headA和headB出发, 当pA跑完了A链以后, 使其从B链头节点继续跑, pB 同理。
当pA=pB时, 要么两者相遇在相交节点, 要么两者同时跑到链表结尾, 即 null = null。
1 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { |
Explanation
当P1 第二次经过交点 I 时, 其走过的距离 = (M + N) + Z;
同理, 当P2 第二次经过交点时, 其走过的距离 = (N + Z ) + M;
两者相等。所以只要有交点, P1 & P2 必相交于交点处。
若两条链没有交点, 假设 ListA = X, ListB = Y.
则当P1 遍历完两条链走到null 时, 其路程为 X + Y。 同理, P2的路程为Y + X。 所以只要两条链表没有相交, 两者必在 null 处相遇。
链表的倒数第K个元素 - offer
- 注意双指针在链表中的使用:
- 倒数第k个元素, 可使快指针先走k步, 然后慢指针再开始走,这样当快指针走到末尾慢指针所指即答案。
- 注意代码鲁棒性:
- 所谓鲁棒性即注意对input的检查, 通常再写算法时表现再程序入口的几个 if-return。 很重要,勿忘。
- 再此题中包括:
- 链表是否为空?
- k是否为0?
- 链表长度是否大于k?
链表的反转
recursive即可
但是注意:
- 不要忘了把原头节点的next置空
- 终止条件应为:
1
2
3
4
5
6
7"""
不应使用cur_node is None 为if条件,因为不好记录新的头节点
"""
if cur_node.next is None:
cur_node.next = pre_node
self.head = cur_node
return