链表应用
目录
链表
链表相关的典型应用如下:
序号 | 题目 |
---|---|
1 | 203. 移除链表元素 |
2 | 86. 分隔链表 |
3 | 206. 反转链表 |
4 | 160. 相交链表 |
5 | 92. 反转链表 II |
应用
应用1:Leetocde.203
题目
解题思路
由于头结点也可能被删除,所以我们事先创建一个哑结点。
遍历过程中,如果遇到相等的节点,则跳过下一个节点,将当前节点的指针指向下下个节点
代码
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
# 由于头结点也可能被删除,所以创建一个哑结点
dummy = ListNode(-1)
dummy.next = head
p = dummy
while p.next:
# 如果遇到相等的节点,则跳过下一个节点,将当前节点的指针指向下下个节点
if p.next.val == val:
p.next = p.next.next
else:
p = p.next
return dummy.next
应用2:Leetocde.86
题目
解题思路
在遍历过程中,将原有的链表分成两部分,使用两个 \(dumy\) 节点 \(large\)、\(small\) ,用于分别记录大于 \(x\) 的节点和小于 \(x\) 的节点,遍历完成之后,将大链表,连接到小链表的结尾即可。
代码实现
class Solution:
def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
small = ListNode(0)
large = ListNode(0)
large_first = large
small_first = small
pointer = head
while pointer:
if pointer.val < x:
small.next = pointer
small = small.next
else:
large.next = pointer
large = large.next
pointer = pointer.next
large.next = None
small.next = large_first.next
return small_first.next
应用3:Leetocde.206
题目
解题思路
双向链表只需要一个节点就可以找到它的前后两个节点,单向链表需要两个节点,才能知道当前节点的前后节点。
单向链表逆序的时候,需要按照如下步骤操作:
- 先用一个临时指针
temp
,指向当前节点的下一个节点; - 将当前节点的
next
指针,指向前一个节点; - 前一个指针,移动一步;
- 后一个指针,移动一步;
如图所示:
代码实现
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
p1 = None
p2 = head
while p2:
temp = p2.next
p2.next = p1
p1 = p2
p2 = temp
return p1
应用4:Leetocde.160
题目
解题思路
用两个指针分别指向两个链表,当指针移动到链表结尾后,再交换两个指针的指向,如果两个链表存在交点,则两个指针会同时相等。
代码
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
p1 = headA
p2 = headB
while p1 != p2:
p1 = headB if not p1 else p1.next
p2 = headA if not p2 else p2.next
return p1
应用5:Leetocde.92
题目
解题思路
遍历一次链表,将中间的子链表倒序,遍历时,记录前驱和后驱节点,倒序完成后,将前驱和后驱节点连接即可。
下面,我们以如下用例,来介绍算法流程:
head = [1,2,3,4,5,6], left = 2, right = 5
步骤如下:
- 初始化两个指针 \(P0\) 和 \(P\),用于记录当前一个节点和当前节点:
- 向后移动 \(left\) 步:
- 初始化两个指针 \(P1\) 和 \(P2\),用于单链表 \([2,3,4,5]\) 倒序:
- 使用一个临时指针 \(Temp\) 记录下一个节点:
- 使用一个 \(P2\) 指向节点的 \(next\) 指针指向 \(P1\) :
- 同时\(P1\) 和 \(P2\) 分别后移一步:
- 重复步骤 \(5\) 和 \(6\),将单链表 \([2,3,4,5]\) 完成倒序:
- 将指针 \(P\) 指向的节点的 next 指针指向 \(P2\) 指向的节点:
- 将指针 \(P0\) 指向的节点的 next 指针指向 \(P1\) 指向的节点:
代码
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
post = head
before = None
# 用指针p移动到left所在的节点
for _ in range(1, left):
before = post
post = post.next
# 将中间的子链表倒序
p1 = None
p2 = post
for _ in range(left, right + 1):
temp = p2.next
p2.next = p1
p1 = p2
p2 = temp
# 记录后驱节点
if post:
post.next = p2
# 将前驱链表指向倒序后的链表表头
if before:
before.next = p1
# 如果前驱节点是head则直接指向p1
else:
head = p1
return head