leetcode-LinkedList

链表问题

单向链表

链表的头插法和尾插法

image-20240531154404853
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class LinkedList:
def __init__(self):
self.head = None

# 头插法
def insert_at_head(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node

# 尾插法
def insert_at_tail(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
return
last_node = self.head
while last_node.next:
last_node = last_node.next
last_node.next = new_node

# 打印链表(用于测试)
def print_list(self):
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")

头插法流程

  1. 创建一个新节点 node。在节点的数据字段中插入项目。
  2. 设置新节点 node 的下一个指针,指向当前头部指向的节点。
  3. 使头部指针 head 指向新添加的节点。
Screenshot 2024-07-12 223136

尾插法流程

  1. 在列表中查找,直到到达最后一个节点。
  2. 使用要插入的项目创建一个新节点。
  3. 将最后一个节点的下一个指针设置为新创建的节点。
  4. 将新节点的下一个指针设置为 null。
Screenshot 2024-07-12 223818

判断链表是否有环 - 快慢指针法

假设有fast和slow两个指针,一个慢一个快,如果链表是有环状的,那么走的快的那个指针迟早会跟慢指针重合

Screenshot 2024-07-12 225644
1
2
3
4
5
6
7
8
9
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
slow = fast = head # 乌龟和兔子同时从起点出发
while fast and fast.next:
slow = slow.next # 乌龟走一步
fast = fast.next.next # 兔子走两步
if fast is slow: # 兔子追上乌龟(套圈),说明有环
return True
return False # 访问到了链表末尾,无环

判断环形链表的公共入口 - 快慢指针法

  1. 假设有fast和slow两个指针,一个慢一个快,如果链表是有环状的,那么走的快的那个指针迟早会跟慢指针重合
  2. 当快慢指针第一次重合的时候,重新将fast指针移动到开头head位置
  3. 当fast和slow指针再次相遇的时候,则是链表的公共入口【此时slow第一次走到入口位置】
Screenshot 2024-07-12 230051
1
2
3
4
5
6
7
8
9
10
11
class Solution(object):
def detectCycle(self, head):
fast, slow = head, head
while True:
if not (fast and fast.next): return
fast, slow = fast.next.next, slow.next
if fast == slow: break
fast = head
while fast != slow:
fast, slow = fast.next, slow.next
return fast

使用虚拟节点dummy的情况:

当你需要创造一条新链表的时候,可以使用虚拟头结点简化边界情况的处理

何时需要切开原来的链表:

如果我们需要把原链表的节点接到新链表上,而不是 new 新节点来组成新链表的话,那么断开节点和原链表之间的链接可能是必要的。那其实我们可以养成一个好习惯,但凡遇到这种情况,就把原链表的节点断开,这样就不会出错了。

双向链表

循环链表