Skip to content

Commit c6cda71

Browse files
committed
init repo
1 parent a4f20ea commit c6cda71

27 files changed

+4487
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

SUMMARY.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# 算法模板
2+
3+
## 入门篇
4+
5+
- [go 语言入门](introduction/golang.md)
6+
- [算法快速入门](introduction/quickstart.md)
7+
8+
## 数据结构篇
9+
10+
- [二叉树](data_structure/binary_tree.md)
11+
- [链表](data_structure/linked_list.md)
12+
- [栈和队列](data_structure/stack_queue.md)
13+
- [二进制](data_structure/binary_op.md)
14+
15+
## 基础算法篇
16+
17+
- [二分搜索](basic_algorithm/binary_search.md)
18+
- [排序算法](basic_algorithm/sort.md)
19+
- [动态规划](basic_algorithm/dp.md)
20+
21+
## 算法思维
22+
23+
- [递归思维](advanced_algorithm/recursion.md)
24+
- [滑动窗口思想](advanced_algorithm/slide_window.md)
25+
- [二叉搜索树](advanced_algorithm/binary_search_tree.md)
26+
- [回溯法](advanced_algorithm/backtrack.md)

advanced_algorithm/backtrack.md

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# 回溯法
2+
3+
## 背景
4+
5+
回溯法(backtrack)常用于遍历列表所有子集,是 DFS 深度搜索一种,一般用于全排列,穷尽所有可能,遍历的过程实际上是一个决策树的遍历过程。时间复杂度一般 O(N!),它不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举,复杂度一般都很高。
6+
7+
## 模板
8+
9+
```go
10+
result = []
11+
func backtrack(选择列表,路径):
12+
if 满足结束条件:
13+
result.add(路径)
14+
return
15+
for 选择 in 选择列表:
16+
做选择
17+
backtrack(选择列表,路径)
18+
撤销选择
19+
```
20+
21+
核心就是从选择列表里做一个选择,然后一直递归往下搜索答案,如果遇到路径不通,就返回来撤销这次选择。
22+
23+
## 示例
24+
25+
### [subsets](https://leetcode-cn.com/problems/subsets/)
26+
27+
> 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
28+
29+
遍历过程
30+
31+
![image.png](../images/backtrack.png)
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+
}
59+
```
60+
61+
### [subsets-ii](https://leetcode-cn.com/problems/subsets-ii/)
62+
63+
> 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。说明:解集不能包含重复的子集。
64+
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+
}
101+
```
102+
103+
### [permutations](https://leetcode-cn.com/problems/permutations/)
104+
105+
> 给定一个   没有重复   数字的序列,返回其所有可能的全排列。
106+
107+
思路:需要记录已经选择过的元素,满足条件的结果才进行返回
108+
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+
}
145+
```
146+
147+
### [permutations-ii](https://leetcode-cn.com/problems/permutations-ii/)
148+
149+
> 给定一个可包含重复数字的序列,返回所有不重复的全排列。
150+
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+
}
193+
```
194+
195+
## 练习
196+
197+
- [ ] [subsets](https://leetcode-cn.com/problems/subsets/)
198+
- [ ] [subsets-ii](https://leetcode-cn.com/problems/subsets-ii/)
199+
- [ ] [permutations](https://leetcode-cn.com/problems/permutations/)
200+
- [ ] [permutations-ii](https://leetcode-cn.com/problems/permutations-ii/)
201+
202+
挑战题目
203+
204+
- [ ] [combination-sum](https://leetcode-cn.com/problems/combination-sum/)
205+
- [ ] [letter-combinations-of-a-phone-number](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/)
206+
- [ ] [palindrome-partitioning](https://leetcode-cn.com/problems/palindrome-partitioning/)
207+
- [ ] [restore-ip-addresses](https://leetcode-cn.com/problems/restore-ip-addresses/)
208+
- [ ] [permutations](https://leetcode-cn.com/problems/permutations/)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy