DAY 24
很经典的回溯算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func combine (n int , k int ) [][]int { ans := [][]int {} curr := []int {} var dfs func (s int ) dfs = func (s int ) { if len (curr) == k { ans = append (ans, append ([]int {}, curr...)) return } for i := s; i <= n; i++ { curr = append (curr, i) dfs(i + 1 ) curr = curr[:len (curr)-1 ] } } dfs(1 ) return ans }
做了一点剪枝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package main func combine(n int, k int) [][]int { ans := [][]int{} curr := []int{} var dfs func(s int) dfs = func(s int) { if len(curr) == k { ans = append(ans, append([]int{}, curr...)) return } - for i := s; i <= n; i++ { + for i := s; i <= n-(k-len(curr))+1; i++ { curr = append(curr, i) dfs(i + 1) curr = curr[:len(curr)-1] } } dfs(1) return ans }
DAY 25
很顺理成章的递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func combinationSum3 (k int , n int ) [][]int { ans := [][]int {} curr := []int {} var dfs func (s, k, n int ) dfs = func (s, k, n int ) { if k == 0 || n < 0 { if n == 0 { ans = append (ans, append ([]int {}, curr...)) } return } for i := s; i <= 9 ; i++ { curr = append (curr, i) dfs(i+1 , k-1 , n-i) curr = curr[:len (curr)-1 ] } } dfs(1 , k, n) return ans }
之前刷的时候写的是 BFS 的,这次特意写了个递归的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var m = [][]string { {}, {}, {"a" , "b" , "c" }, {"d" , "e" , "f" }, {"g" , "h" , "i" }, {"j" , "k" , "l" }, {"m" , "n" , "o" }, {"p" , "q" , "r" , "s" }, {"t" , "u" , "v" }, {"w" , "x" , "y" , "z" }, } func letterCombinations (digits string ) []string { n := len (digits) if n == 0 { return []string {} }else if n == 1 { return m[int (digits[0 ]-'0' )] } ans := []string {} pre := letterCombinations(digits[1 :]) for _, i := range pre { for _, j := range m[int (digits[0 ]-'0' )] { ans = append (ans, j+i) } } return ans }
DAY 26
周日休息,去逛了 Gopher China(
DAY 27
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func combinationSum (candidates []int , target int ) [][]int { n := len (candidates) ans := [][]int {} curr := []int {} var dfs func (idx, need int ) dfs = func (idx, need int ) { if need < 0 { return } else if need == 0 { ans = append (ans, append ([]int {}, curr...)) } for i := idx; i < n; i++ { curr = append (curr, candidates[i]) dfs(i, need-candidates[i]) curr = curr[:len (curr)-1 ] } } dfs(0 , target) return ans }
这道题麻烦的地方在于去重,真得看代码随想录
如果与前一个元素相同且前一个元素没有使用过,则跳过
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 func combinationSum2 (candidates []int , target int ) [][]int { n := len (candidates) sort.Ints(candidates) ans := [][]int {} curr := []int {} used := make ([]bool , n) var dfs func (idx, need int ) dfs = func (idx, need int ) { if need < 0 { return } else if need == 0 { ans = append (ans, append ([]int {}, curr...)) } for i := idx; i < n; i++ { if i > 0 && candidates[i] == candidates[i-1 ] && !used[i-1 ] { continue } curr = append (curr, candidates[i]) used[i] = true dfs(i+1 , need-candidates[i]) curr = curr[:len (curr)-1 ] used[i] = false } } dfs(0 , target) return ans }
这道题貌似还可以用 dp
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 30 31 32 33 34 35 func partition (s string ) [][]string { ans := [][]string {} curr := []string {} var dfs func (s string ) dfs = func (s string ) { n := len (s) if n == 0 { ans = append (ans, append ([]string {}, curr...)) return } for i := 1 ; i <= n; i++ { if isPalindrome(s[:i]) { curr = append (curr, s[:i]) dfs(s[i:]) curr = curr[:len (curr)-1 ] } } } dfs(s) return ans } func isPalindrome (s string ) bool { if len (s) == 1 { return true } else if len (s) == 2 { if s[0 ] == s[1 ] { return true } else { return false } } else { return s[0 ] == s[len (s)-1 ] && isPalindrome(s[1 :len (s)-1 ]) } }
DAY 28
细节有点多,需要注意
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 func restoreIpAddresses (s string ) []string { ans := []string {} curr := []string {} var dfs func (s string ) dfs = func (s string ) { if len (curr) == 4 || s == "" { if len (curr) == 4 && s == "" { ans = append (ans, combine(curr)) } return } if s[0 ] == '0' { curr = append (curr, string (s[0 ])) dfs(s[1 :]) curr = curr[:len (curr)-1 ] return } for i := 1 ; i <= len (s); i++ { if atoi(s[:i]) > 255 { break } curr = append (curr, s[:i]) dfs(s[i:]) curr = curr[:len (curr)-1 ] } } dfs(s) return ans } func atoi (s string ) int { ans := 0 for _, ch := range s { ans = ans*10 + int (ch) - '0' } return ans } func combine (s []string ) string { ans := "" for _, item := range s { ans = ans + item + "." } return ans[:len (ans)-1 ] }
一气呵成,非常舒服
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func subsets (nums []int ) [][]int { ans := [][]int {} curr := []int {} targetLen := 0 var dfs func (nums []int ) dfs = func (nums []int ) { if len (curr) == targetLen { ans = append (ans, append ([]int {}, curr...)) return } for i := 0 ; i < len (nums); i++ { curr = append (curr, nums[i]) dfs(nums[i+1 :]) curr = curr[:len (curr)-1 ] } } for targetLen = 0 ; targetLen <= len (nums); targetLen++ { dfs(nums) } return ans }
为了去重,有一点小小的 diff
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 func subsetsWithDup(nums []int) [][]int { + sort.Ints(nums) ans := [][]int{} curr := []int{} targetLen := 0 var dfs func(nums []int) dfs = func(nums []int) { if len(curr) == targetLen { ans = append(ans, append([]int{}, curr...)) return } for i := 0; i < len(nums); i++ { + if i > 0 && nums[i] == nums[i-1] { + continue + } curr = append(curr, nums[i]) dfs(nums[i+1:]) curr = curr[:len(curr)-1] } } for targetLen = 0; targetLen <= len(nums); targetLen++ { dfs(nums) } return ans }
DAY 29
这道题去重是关键, 我一开始去重写错了,后来喂给 GPT 他把我教会了
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 func findSubsequences (nums []int ) [][]int { var ans [][]int var curr []int var dfs func (nums []int ) dfs = func (nums []int ) { if len (curr) >= 2 { ans = append (ans, append ([]int {}, curr...)) } used := map [int ]bool {} for i := 0 ; i < len (nums); i++ { if used[nums[i]] { continue } if len (curr) > 0 && curr[len (curr)-1 ] > nums[i] { continue } used[nums[i]] = true curr = append (curr, nums[i]) dfs(nums[i+1 :]) curr = curr[:len (curr)-1 ] } } dfs(nums) return ans }
这个 map 的作用是在当前层不重复,比如 [4,6,7,7]
,你不去重就会搜到两个 [4,6,7]
而使用 map,当你搜到 4->6
的时候,搜到第一个 7,把 7 标记一下,下一个 7 就能跳过了
向下递归的时候在可选集合中剔除当前元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func permute (nums []int ) [][]int { ans := [][]int {} curr := []int {} var dfs func (nums []int ) dfs = func (nums []int ) { if len (nums) == 0 { ans = append (ans, append ([]int {}, curr...)) return } for i := 0 ; i < len (nums); i++ { curr = append (curr, nums[i]) tmp := append ([]int {}, nums[:i]...) tmp = append (tmp, nums[i+1 :]...) dfs(tmp) curr = curr[:len (curr)-1 ] } } dfs(nums) return ans }
或者你可以使用一个 []bool
标记已经剔除的元素
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 func permute (nums []int ) [][]int { n := len (nums) ans := [][]int {} curr := []int {} used := make ([]bool , n) var dfs func (depth int ) dfs = func (depth int ) { if depth == n { ans = append (ans, append ([]int {}, curr...)) return } for i := 0 ; i < n; i++ { if used[i] { continue } curr = append (curr, nums[i]) used[i] = true dfs(depth + 1 ) used[i] = false curr = curr[:len (curr)-1 ] } } dfs(0 ) return ans }
与 [40.组合总和 II](#40.组合总和 II) 的去重思路相同,首先排序
然后如果用过,或者与前一个相同并且前一个没用过,就跳过
(当我们有连续的重复元素时,为了避免生成相同的排列,我们只在这些重复元素的第一次出现时考虑它们)
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 - func permute(nums []int) [][]int { + func permuteUnique(nums []int) [][]int { n := len(nums) + sort.Ints(nums) ans := [][]int{} curr := []int{} used := make([]bool, n) var dfs func(depth int) dfs = func(depth int) { if depth == n { ans = append(ans, append([]int{}, curr...)) return } for i := 0; i < n; i++ { - if used[i] { + if used[i] || (i > 0 && nums[i] == nums[i-1] && !used[i-1]) { continue } curr = append(curr, nums[i]) used[i] = true dfs(depth + 1) used[i] = false curr = curr[:len(curr)-1] } } dfs(0) return ans }
DAY 30
泻药,欧拉回路,还是算了
经典 N 皇后,看了一眼,有点忙不想做
一样