代码随想录算法训练营第二十五天 | 216. 组合总和 III、17. 电话号码的字母组合

53 阅读2分钟

216. 组合总和 III

链接

文章链接

题目链接

第一想法

还是套公式,为了防止一个数用多次,所以需要用startIndex来控制,同时需要一个sum来记录总和,代码如下:

 function combinationSum3(k: number, n: number): number[][] {
    let res:number[][]=[]
    const dfs=(arr:number[],startIndex:number,sum:number)=>{
        if(arr.length>=k){
            if(sum===n) res.push(Array.from(arr))
            return
        }
        for(let i=startIndex;i<=9;i++){
            arr.push(i)
            sum+=i
            dfs(arr,i+1,sum)
            arr.pop()
            sum-=i
        }
    }
    dfs([],1,0)
    return res
  };

看完文章后的想法

文章的想法和我的想法是一致的,看完文章后主要来讲讲剪枝的思路,如何剪枝? 存在这么一种情况,arr.length未达到k但是sum已经大于n了,这种情况下就需要剪枝:

image.png 代码如下:

function combinationSum3(k: number, n: number): number[][] {
  let res:number[][]=[]
  const dfs=(arr:number[],startIndex:number,sum:number)=>{
      if(sum>n) return 
      if(arr.length>=k){
          if(sum===n) res.push(Array.from(arr))
          return
      }
      for(let i=startIndex;i<=9;i++){
          arr.push(i)
          sum+=i
          dfs(arr,i+1,sum)
          arr.pop()
          sum-=i
      }
  }
  dfs([],1,0)
  return res
};

思考

由于昨天做过组合,所以今天做这道题的时候很容易上手,但是没有想到剪枝操作,目前做了两道题,都是可以写出解题但是优化剪枝想不到.

17. 电话号码的字母组合

链接

文章链接

题目链接

第一想法

首先要想如何数组和字母映射,所以准备了一个数组array用于映射,同是由于ts无法删除字符,所以换了一种回溯,其中蕴含着回溯,代码如下:

 function letterCombinations(digits: string): string[] {
    let array: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']]//映射表
    let res:string[]=[]
    let len:number=digits.length
    const dfs=(str:string,digits: string,index:number)=>{
        if(str.length==len){
            str&&res.push(str) //防止str为""的情况
            return
        }
        for(let i=0;i<array[Number(digits[index])-2].length;i++){
            let s:string=str
            s+=array[Number(digits[index])-2][i] //s这里是隐藏回溯的
            dfs(s,digits,index+1)
        }
    }
    dfs('',digits,0)
    return res
   };

看完文章后的想法

文章的想法和我的想法是一致的,不过文章中不是用隐含回溯,而是用的是数组,这样的回溯就比较明显了,同时映射表我用的是二维数组,也可以用一位数组+字符串就可以了,也可以用对象的形式,映射表代码如下:

    const strMap: { [index: number]: string[] } = {
        2: ['a', 'b', 'c'],
        3: ['d', 'e', 'f'],
        4: ['g', 'h', 'i'],
        5: ['j', 'k', 'l'],
        6: ['m', 'n', 'o'],
        7: ['p', 'q', 'r', 's'],
        8: ['t', 'u', 'v'],
        9: ['w', 'x', 'y', 'z']
    }

思考

这道题和组合那种题是不一样的,因为数字是可以重复的,所以循环是可以从0开始的,其次,由于在ts&js中是无法直接去字符串的某个字符删除的,所以有两种方法,一种是我那种创建一个s:string进行隐式回溯,另一种就是按照文章中用数组arr,这样可以很明显的看出是有回溯存在的

今日总结

今日耗时2小时,两道题都不算难,但是两道题有所差别,第一道考了如何不重复数字,第二道题是可以重复(有无startIndex),同时由于ts&js无法删减字符,所以考了如何利用字符进行回溯,总体来说不难.