@@ -30,166 +30,160 @@ func backtrack(选择列表,路径):
30
30
31
31
![ image.png] ( https://img.fuiboom.com/img/backtrack.png )
32
32
33
- ``` go
34
- func subsets (nums []int ) [][]int {
35
- // 保存最终结果
36
- result := make ([][]int , 0 )
37
- // 保存中间结果
38
- list := make ([]int , 0 )
39
- backtrack (nums, 0 , list, &result)
40
- return result
41
- }
42
-
43
- // nums 给定的集合
44
- // pos 下次添加到集合中的元素位置索引
45
- // list 临时结果集合(每次需要复制保存)
46
- // result 最终结果
47
- func backtrack (nums []int , pos int , list []int , result *[][]int ) {
48
- // 把临时结果复制出来保存到最终结果
49
- ans := make ([]int , len (list))
50
- copy (ans, list)
51
- *result = append (*result, ans)
52
- // 选择、处理结果、再撤销选择
53
- for i := pos; i < len (nums); i++ {
54
- list = append (list, nums[i])
55
- backtrack (nums, i+1 , list, result)
56
- list = list[0 : len (list)-1 ]
57
- }
58
- }
33
+ ``` Python
34
+ class Solution :
35
+ def subsets (self , nums : List[int ]) -> List[List[int ]]:
36
+
37
+ n = len (nums)
38
+ result = []
39
+
40
+ route = []
41
+ def backtrack (start , k ):
42
+ if len (route) == k:
43
+ result.append(route.copy())
44
+ return
45
+
46
+ for i in range (start, n):
47
+ route.append(nums[i])
48
+ backtrack(i + 1 , k)
49
+ route.pop()
50
+
51
+ return
52
+
53
+ for k in range (n + 1 ):
54
+ backtrack(0 , k)
55
+
56
+ return result
59
57
```
60
58
61
59
### [ subsets-ii] ( https://leetcode-cn.com/problems/subsets-ii/ )
62
60
63
61
> 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。说明:解集不能包含重复的子集。
64
62
65
- ``` go
66
- import (
67
- " sort"
68
- )
69
-
70
- func subsetsWithDup (nums []int ) [][]int {
71
- // 保存最终结果
72
- result := make ([][]int , 0 )
73
- // 保存中间结果
74
- list := make ([]int , 0 )
75
- // 先排序
76
- sort.Ints (nums)
77
- backtrack (nums, 0 , list, &result)
78
- return result
79
- }
80
-
81
- // nums 给定的集合
82
- // pos 下次添加到集合中的元素位置索引
83
- // list 临时结果集合(每次需要复制保存)
84
- // result 最终结果
85
- func backtrack (nums []int , pos int , list []int , result *[][]int ) {
86
- // 把临时结果复制出来保存到最终结果
87
- ans := make ([]int , len (list))
88
- copy (ans, list)
89
- *result = append (*result, ans)
90
- // 选择时需要剪枝、处理、撤销选择
91
- for i := pos; i < len (nums); i++ {
92
- // 排序之后,如果再遇到重复元素,则不选择此元素
93
- if i != pos && nums[i] == nums[i-1 ] {
94
- continue
95
- }
96
- list = append (list, nums[i])
97
- backtrack (nums, i+1 , list, result)
98
- list = list[0 : len (list)-1 ]
99
- }
100
- }
63
+ ``` Python
64
+ class Solution :
65
+ def subsetsWithDup (self , nums : List[int ]) -> List[List[int ]]:
66
+
67
+ nums = sorted (nums)
68
+ n = len (nums)
69
+ result = []
70
+
71
+ route = []
72
+ def backtrack (start , k ):
73
+
74
+ if len (route) == k:
75
+ result.append(route.copy())
76
+ return
77
+
78
+ last = None
79
+ for i in range (start, n):
80
+ if nums[i] != last:
81
+ route.append(nums[i])
82
+ backtrack(i + 1 , k)
83
+ last = route.pop()
84
+
85
+ return
86
+
87
+ for k in range (n + 1 ):
88
+ backtrack(0 , k)
89
+
90
+ return result
101
91
```
102
92
103
93
### [ permutations] ( https://leetcode-cn.com/problems/permutations/ )
104
94
105
95
> 给定一个 没有重复 数字的序列,返回其所有可能的全排列。
106
96
107
- 思路:需要记录已经选择过的元素,满足条件的结果才进行返回
97
+ 思路 1:需要记录已经选择过的元素,满足条件的结果才进行返回,需要额外 O(n) 的空间
98
+
99
+ ``` Python
100
+ class Solution :
101
+ def permute (self , nums : List[int ]) -> List[List[int ]]:
102
+
103
+ n = len (nums)
104
+ result = []
105
+
106
+ in_route = [False ] * n
107
+
108
+ def backtrack (route = []):
109
+
110
+ if len (route) == n:
111
+ result.append(route.copy())
112
+ return
113
+
114
+ for i in range (n):
115
+ if not in_route[i]:
116
+ route.append(nums[i])
117
+ in_route[i] = True
118
+ backtrack()
119
+ route.pop()
120
+ in_route[i] = False
121
+
122
+ return
123
+
124
+ backtrack()
125
+ return result
126
+ ```
108
127
109
- ``` go
110
- func permute (nums []int ) [][]int {
111
- result := make ([][]int , 0 )
112
- list := make ([]int , 0 )
113
- // 标记这个元素是否已经添加到结果集
114
- visited := make ([]bool , len (nums))
115
- backtrack (nums, visited, list, &result)
116
- return result
117
- }
118
-
119
- // nums 输入集合
120
- // visited 当前递归标记过的元素
121
- // list 临时结果集(路径)
122
- // result 最终结果
123
- func backtrack (nums []int , visited []bool , list []int , result *[][]int ) {
124
- // 返回条件:临时结果和输入集合长度一致 才是全排列
125
- if len (list) == len (nums) {
126
- ans := make ([]int , len (list))
127
- copy (ans, list)
128
- *result = append (*result, ans)
129
- return
130
- }
131
- for i := 0 ; i < len (nums); i++ {
132
- // 已经添加过的元素,直接跳过
133
- if visited[i] {
134
- continue
135
- }
136
- // 添加元素
137
- list = append (list, nums[i])
138
- visited[i] = true
139
- backtrack (nums, visited, list, result)
140
- // 移除元素
141
- visited[i] = false
142
- list = list[0 : len (list)-1 ]
143
- }
144
- }
128
+ 思路 2: 针对此题的更高级的回溯,利用原有的数组,每次回溯将新选择的元素与当前位置元素交换,回溯完成再换回来
129
+
130
+ ``` Python
131
+ class Solution :
132
+ def permute (self , nums : List[int ]) -> List[List[int ]]:
133
+
134
+ n = len (nums)
135
+ result = []
136
+
137
+ def backtrack (idx = 0 ):
138
+ if idx == n:
139
+ result.append(nums.copy())
140
+ for i in range (idx, n):
141
+ nums[idx], nums[i] = nums[i], nums[idx]
142
+ backtrack(idx + 1 )
143
+ nums[idx], nums[i] = nums[i], nums[idx]
144
+ return
145
+
146
+ backtrack()
147
+ return result
145
148
```
146
149
150
+
151
+
147
152
### [ permutations-ii] ( https://leetcode-cn.com/problems/permutations-ii/ )
148
153
149
154
> 给定一个可包含重复数字的序列,返回所有不重复的全排列。
150
155
151
- ``` go
152
- import (
153
- " sort"
154
- )
155
-
156
- func permuteUnique (nums []int ) [][]int {
157
- result := make ([][]int , 0 )
158
- list := make ([]int , 0 )
159
- // 标记这个元素是否已经添加到结果集
160
- visited := make ([]bool , len (nums))
161
- sort.Ints (nums)
162
- backtrack (nums, visited, list, &result)
163
- return result
164
- }
165
-
166
- // nums 输入集合
167
- // visited 当前递归标记过的元素
168
- // list 临时结果集
169
- // result 最终结果
170
- func backtrack (nums []int , visited []bool , list []int , result *[][]int ) {
171
- // 临时结果和输入集合长度一致 才是全排列
172
- if len (list) == len (nums) {
173
- subResult := make ([]int , len (list))
174
- copy (subResult, list)
175
- *result = append (*result, subResult)
176
- }
177
- for i := 0 ; i < len (nums); i++ {
178
- // 已经添加过的元素,直接跳过
179
- if visited[i] {
180
- continue
181
- }
182
- // 上一个元素和当前相同,并且没有访问过就跳过
183
- if i != 0 && nums[i] == nums[i-1 ] && !visited[i-1 ] {
184
- continue
185
- }
186
- list = append (list, nums[i])
187
- visited[i] = true
188
- backtrack (nums, visited, list, result)
189
- visited[i] = false
190
- list = list[0 : len (list)-1 ]
191
- }
192
- }
156
+ 注意此题(貌似)无法使用上题的思路 2,因为交换操作会打乱排序。
157
+
158
+ ``` Python
159
+ class Solution :
160
+ def permuteUnique (self , nums : List[int ]) -> List[List[int ]]:
161
+
162
+ nums = sorted (nums)
163
+ n = len (nums)
164
+ result = []
165
+
166
+ in_route = [False ] * n
167
+
168
+ def backtrack (route = []):
169
+
170
+ if len (route) == n:
171
+ result.append(route.copy())
172
+ return
173
+
174
+ last = None
175
+ for i in range (n):
176
+ if not in_route[i] and nums[i] != last:
177
+ route.append(nums[i])
178
+ in_route[i] = True
179
+ backtrack()
180
+ last = route.pop()
181
+ in_route[i] = False
182
+
183
+ return
184
+
185
+ backtrack()
186
+ return result
193
187
```
194
188
195
189
## 练习
@@ -205,4 +199,3 @@ func backtrack(nums []int, visited []bool, list []int, result *[][]int) {
205
199
- [ ] [ letter-combinations-of-a-phone-number] ( https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ )
206
200
- [ ] [ palindrome-partitioning] ( https://leetcode-cn.com/problems/palindrome-partitioning/ )
207
201
- [ ] [ restore-ip-addresses] ( https://leetcode-cn.com/problems/restore-ip-addresses/ )
208
- - [ ] [ permutations] ( https://leetcode-cn.com/problems/permutations/ )
0 commit comments