Skip to content

Commit 1cd9cb7

Browse files
committed
链表交换
1 parent 02c3f78 commit 1cd9cb7

File tree

5 files changed

+276
-0
lines changed

5 files changed

+276
-0
lines changed

专题/链表/交换/206.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Definition for singly-linked list.
2+
# class ListNode:
3+
# def __init__(self, x):
4+
# self.val = x
5+
# self.next = None
6+
7+
class Solution:
8+
def reverseList(self, head: ListNode) -> ListNode:
9+
"""
10+
递归
11+
"""
12+
if head == None or head.next == None:
13+
return head
14+
p = self.reverseList(head.next)
15+
head.next.next = head
16+
head.next = None
17+
return p
18+
19+
20+
class Solution:
21+
def reverseList(self, head: ListNode) -> ListNode:
22+
"""
23+
迭代
24+
"""
25+
final_list = None
26+
while head:
27+
temp = head.next
28+
head.next = final_list
29+
final_list = head
30+
head = temp
31+
return final_list

专题/链表/交换/24.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Definition for singly-linked list.
2+
# class ListNode:
3+
# def __init__(self, val=0, next=None):
4+
# self.val = val
5+
# self.next = next
6+
7+
class Solution:
8+
def swapPairs(self, head: ListNode) -> ListNode:
9+
if head == None or head.next == None:
10+
return head
11+
next_node = head.next
12+
head.next = self.swapPairs(next_node.next)
13+
next_node.next = head
14+
return next_node

专题/链表/交换/25.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Definition for singly-linked list.
2+
# class ListNode:
3+
# def __init__(self, val=0, next=None):
4+
# self.val = val
5+
# self.next = next
6+
7+
def swap(head: ListNode):
8+
final_list = None
9+
while head:
10+
temp = head.next
11+
head.next = final_list
12+
final_list = head
13+
head = temp
14+
15+
return final_list
16+
17+
class Solution:
18+
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
19+
if k == 1 or head == None:
20+
return head
21+
22+
end = head
23+
for _ in range(k-1):
24+
end = end.next # 向后的
25+
if end == None:
26+
return head
27+
end_next = end.next
28+
end.next = None # 放空
29+
# 交换一下
30+
swap(head)
31+
# 拼起来
32+
head.next = self.reverseKGroup(end_next, k)
33+
return end

专题/链表/交换/README.md

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# 链表交换专题
2+
3+
4+
5+
## 1. 基础,一个单链表的交换
6+
7+
这里以[Leetcode 206](https://leetcode-cn.com/problems/reverse-linked-list/) 为例子.
8+
9+
> 206.反转链表
10+
> 反转一个单链表。
11+
>
12+
> 示例:
13+
>
14+
> 输入: 1->2->3->4->5->NULL
15+
> 输出: 5->4->3->2->1->NULL
16+
> 进阶:
17+
> 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
18+
> 版权由Leetcode所有,如有侵权,请联系删除
19+
20+
也是一个很基础的模板
21+
22+
首先说第一种思想:直接使用迭代,然后用头插法的方式,再将所有的Node插入新链表中,因为头插法是反向插入的,因此会起到反转的效果
23+
24+
这种的思路也很简单
25+
26+
1. 创建一个None做链表头。
27+
2. 迭代当前链表,将当前链表的Node插入新链表。
28+
29+
```python
30+
class Solution:
31+
def reverseList(self, head: ListNode) -> ListNode:
32+
"""
33+
迭代
34+
"""
35+
final_list = None
36+
while head:
37+
temp = head.next
38+
head.next = final_list
39+
final_list = head
40+
head = temp
41+
return final_list
42+
```
43+
其中`final_list`是新链表的head位置,初始为NULL,然后使用一个`while`循环去迭代,当前的链表`head`,然后使用头插法一步一步的将Node插入。
44+
45+
递归:
46+
47+
递归的思路主要集中在:
48+
1. `reverseList` 将`head.next`部分的链表反转,例如要反转的链表是`[1,2,3,4]`, 首先先将`[2,3,4]`进行反转为`[4, 3, 2]`
49+
2. 将`head`放在最后,例如: 然后将`[1]`放在`[4, 3, 2]`的后面`[4,3,2,1]`
50+
51+
> note: 这个思路有一个问题:如何找到2能捕获2的指针从而完成操作`2->next = 1`,最简单的思路是直接去遍历,但是很浪费事件,这里可以直接采用递归体中,先对后面的进行反转,然后再拼接前半部分的顺序,此时`[1]`的next其实依旧指向`[2]`,因此我们可以直接这样捕获,避免重新去查找。
52+
53+
形成代码
54+
55+
```python
56+
57+
class Solution:
58+
def reverseList(self, head: ListNode) -> ListNode:
59+
if head == None or head.next == None: # 防止出现None指针操作
60+
return head
61+
p = self.reverseList(head.next)
62+
head.next.next = head
63+
head.next = None
64+
return p
65+
```
66+
67+
## 2. 进一步提升,如果要两两替换呢?
68+
69+
这里使用[Leetcode 24](https://leetcode-cn.com/problems/swap-nodes-in-pairs/)来说明这个问题。
70+
71+
> 24.两两交换链表中的节点
72+
> 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
73+
>
74+
> 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
75+
![](./swap_ex1.jpg)
76+
>
77+
> 输入:head = [1,2,3,4]
78+
> 输出:[2,1,4,3]
79+
> 示例 2:
80+
>
81+
> 输入:head = []
82+
> 输出:[]
83+
> 示例 3:
84+
>
85+
> 输入:head = [1]
86+
> 输出:[1]
87+
>  
88+
> 提示:
89+
>
90+
> 链表中节点的数目在范围 [0, 100] 内
91+
> 0 <= Node.val <= 100
92+
>
93+
> 来源:力扣(LeetCode)
94+
> 链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs
95+
> 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
96+
97+
这个依旧分为两个思路:迭代和递归
98+
99+
迭代:向后移动两个指针然后交换
100+
101+
迭代这里给两个版本
102+
1. 需要使用指针的指针进行操作,因为需要获取到两个节点中前一个节点中的前一个节点的指针,在`python`中一般使用一个临时节点来充当指针的指针例如很多题解中的`dummy = ListNode(-1)`,另一方面也是增加一个头节点方便操作。如果是`C/C++`即可直接使用`**ListNode`
103+
```python
104+
class Solution:
105+
def swapPairs(self, head: ListNode) -> ListNode:
106+
head_pointer = ListNode(-1) # 指针的指针,头节点
107+
pre = head_pointer
108+
pre.next = head
109+
first, second = None, None # 两个节点中的第一个节点和第二个节点
110+
while head and head.next: # next 为 null即可退出
111+
first = head
112+
second = head.next
113+
pre.next = second #交换两节点
114+
first.next = second.next
115+
second.next = first
116+
117+
pre = first #继续遍历后续节点
118+
head = first.next
119+
return head_pointer.next
120+
121+
```
122+
2. 直接进行值交换
123+
```python
124+
class Solution:
125+
def swapPairs(self, head: ListNode) -> ListNode:
126+
if head == None:
127+
return head
128+
129+
first, second = head, head.next
130+
while second != None:
131+
first.val, second.val = second.val, first.val
132+
133+
first = second.next
134+
if first == None:
135+
break
136+
second = first.next
137+
138+
return head
139+
```
140+
141+
递归:向前移动两个指针,先将后半部分交换,再将当前位置交换,然后拼接.
142+
143+
```python
144+
class Solution:
145+
def swapPairs(self, head: ListNode) -> ListNode:
146+
if head == None or head.next == None:
147+
return head
148+
next_node = head.next
149+
head.next = self.swapPairs(next_node.next)
150+
next_node.next = head
151+
return next_node
152+
```
153+
154+
155+
## 3. 任意顺序的K个节点交换
156+
157+
这里使用,[Leetcode25 K个一组翻转链表](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/)作为例子。
158+
159+
160+
由于K个交换过于复杂,这里没有采用迭代的思路,因为迭代的思路需要使用栈存储便利后的一些节点。使用递归思路和代码都比较简答。
161+
162+
首先将问题分为两个部分:
163+
1. K个节点如何交换。这个其实可以转化为问题1,直接套用问题一的模板即可。
164+
2. 判断k个节点的范围。
165+
166+
```python
167+
168+
def swap(head: ListNode):
169+
final_list = None
170+
while head:
171+
temp = head.next
172+
head.next = final_list
173+
final_list = head
174+
head = temp
175+
176+
return final_list
177+
178+
class Solution:
179+
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
180+
if k == 1 or head == None:
181+
return head
182+
183+
end = head
184+
# 向后找k个节点
185+
for _ in range(k-1):
186+
end = end.next # 向后的
187+
if end == None:
188+
return head
189+
end_next = end.next
190+
# end之后置空,方便swap函数进行判断
191+
end.next = None
192+
# 交换一下
193+
swap(head)
194+
# 拼起来
195+
head.next = self.reverseKGroup(end_next, k)
196+
```
197+
198+
时间复杂度为`O(n)`刚好扫描过所有的链表。空间复杂度由于是递归的问题存在一定的递归栈空间复杂度是`O(n/k)`

专题/链表/交换/swap_ex1.jpg

15.3 KB
Loading

0 commit comments

Comments
 (0)