代码随想录day22|216组合总和III17电话号码的字母组合|01笔记

102 阅读1分钟
  • 216组合总和III

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 组合相关的题,首先想到利用回溯法解决,判定条件为有k个元素以及和为n。
  • 解题代码

  • sum单独运算:

  •      var (
             path []int
             result [][]int
         )
         func combinationSum3(k int, n int) [][]int {
             path, result = make([]int, 0), make([][]int, 0)
             backtracking(k, n, 1)
             return result
         }
         
         func backtracking(k int,n int, index int) {
             sum := 0
             for _, num:=range path {
                 sum += num
             }
             if len(path)==k {   
                 if sum == n {
                     tmp := make([]int, k)
                     copy(tmp, path)
                     result = append(result, tmp)
                 }
                 return
             } 
             if sum+(index+(k-len(path)-1)+index)*(k-len(path))/2 <= n {
                 for i:=index;i<=9;i++ {
                     path = append(path, i)
                     backtracking(k, n, i+1)
                     path = path[:len(path)-1]
                 }
             }
             
         }
    
  • 注意事项:剪枝操作
  •      if sum+(index+(k-len(path)-1)+index)*(k-len(path))/2 <= n {
                 for i:=index;i<=9;i++ {
                     path = append(path, i)
                     backtracking(k, n, i+1)
                     path = path[:len(path)-1]
                 }
             }
    
  • sum+(index+(k-len(path)-1)+index)*(k-len(path))/2 <= n
  • 剪枝逻辑是,当剩余可以添加的数从index开始一定至少+1,若按照+1的等差之和与sum相加大于n,则剪枝。于是用首尾相加的公式进行判断。index为首,(index+(k-len(path)-1)为尾,项数是k-len(path)
  • sum传参:

  •      var (
             res [][]int
             path  []int
         )
         func combinationSum3(k int, n int) [][]int {
             res, path = make([][]int, 0), make([]int, 0, k)
             dfs(k, n, 1, 0)
             return res
         }
         
         func dfs(k, n int, start int, sum int) {
             if len(path) == k {
                 if sum == n {
                     tmp := make([]int, k)
                     copy(tmp, path)
                     res = append(res, tmp)
                 }
                 return
             }
             for i := start; i <= 9; i++ {
                 if sum + i > n || 9-i+1 < k-len(path) {
                     break
                 }
                 path = append(path, i)
                 dfs(k, n, i+1, sum+i)
                 path = path[:len(path)-1]
             }
         }
    
  • 17电话号码的字母组合

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 构建数字与字母的映射关系。然后通过回溯查找构建结果集。
  • 遇到问题

    • 循环方式取值不对应
      image.png
  • 解决方法:
  • 将针对str的for range循环替换成 for i++循环。
    • 下标越界:
      image.png
  • 解决方法:
  • digit :=int(digits[idx]) 改为digit :=int(digits[idx] - '0')
  • 解题代码

  •     var ans []string
        var path []byte
        var hash map[int]string = map[int]string{
            2:"abc",
            3:"def",
            4:"ghi",
            5:"jkl",
            6:"mno",
            7:"pqrs",
            8:"tuv",
            9:"wxyz",
        }
        // m = []string{("", "",) "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}
        //也可以直接用数组,不过要注意下标的位置。或者在后面的digits调整-2.
        
        func backTrav(digits string, idx int) {
        	//if idx > len(path) {    //配合取循环的剪枝
            //    return
            //}
            if len(path) == len(digits) {
                temp := string(path)
                ans = append(ans, temp)
                return
            }
        
            digit := int(digits[idx])    //本质上是用idx代替了第一层循环的指针
            str := hash[digit]
            for j := 0; j < len(str); j++ {
                path = append(path, str[j])
                backTrav(digits, idx+1)
                path = path[:len(path)-1]
            }
            
            // for i:=idx;i<len(digits);i++ {    
            //     num := int(digits[i] - '0')
            //     str := hash[num]
            //     for  j := 0; j < len(str); j++ {
            //         path = append(path, str[j])
            //         backTrav(digits, i + 1) //取循环的方式会造成最后一个值的重复选取,需要用越界剪枝
            //         path = path[:len(path)-1]
            //     }
            // }
            return
        
        }
        
        func letterCombinations(digits string) []string {
            ans = []string{}
            path = []byte{}
            if digits == "" {
                return ans
            }
            backTrav(digits, 0)
            
            return ans
        }