IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    『代码随想录』回溯(Backtracking)

    NX の 博客发表于 2023-11-17 03:41:16
    love 0

    DAY 24

    77.组合

    很经典的回溯算法

    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

    216.组合总和 III

    很顺理成章的递归

    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
    }

    17.电话号码的字母组合

    之前刷的时候写的是 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

    39.组合总和

    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
    }

    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 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
    }

    131.分割回文串

    这道题貌似还可以用 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

    93.复原 IP 地址

    细节有点多,需要注意

    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]
    }

    78.子集

    一气呵成,非常舒服

    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
    }

    90.子集 II

    为了去重,有一点小小的 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

    491.递增子序列

    这道题去重是关键, 我一开始去重写错了,后来喂给 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 就能跳过了

    46.全排列

    向下递归的时候在可选集合中剔除当前元素

    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
    }

    47. 全排列 II

    与 [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

    332. 重新安排行程

    泻药,欧拉回路,还是算了

    51. N 皇后

    经典 N 皇后,看了一眼,有点忙不想做

    37. 解数独

    一样



沪ICP备19023445号-2号
友情链接