39. 组合总和
链接
文章链接
题目链接
第一想法
这道题如果不算去重的话很简单,按照三部曲写就可以了,但是现在的问题是需要去重,我的想法是利用指向标来解决问题,代码如下:
function combinationSum(candidates: number[], target: number): number[][] {
let res:number[][]=[]
candidates.sort((a,b)=>a-b) //非常重要的一步 只有排列好了之后才能完整的去重
const foo=(arr: number[], target: number,sum:number,order:number)=>{
if(sum==target){ //终止条件一
res.push(Array.from(arr))
return
}
if(sum>target) return //终止条件2
for(let i=0;i<candidates.length;i++){ //可以重复 所以都从0开始
if(candidates[i]<order) continue//去重 很重要的一步 例如排列好后的结果为[2,2,3],[2,3,2].order是上层递归的元素,因为要求当前递归的元素要大于等于上层递归的元素,所以[2,3,2]这个是不符合要求的 被去掉
arr.push(candidates[i])
sum+=candidates[i]
foo(arr,target,sum,candidates[i])
sum-=candidates[i] //回溯
arr.pop()//回溯
}
}
foo([],target,0,0)
return res
};
看完文章的想法
文章的想法确实简单,我是通过指向标来进行去重的,而文章中是利用startIndex进行去重的,同时也避免了使用nums.sort(),所以是比我更优的,同时也可以进行剪枝,因为如果sum>target的话还是进入了下一层递归,可以在for添加条件让其终止在本层,代码如下:
function combinationSum(candidates: number[], target: number): number[][] {
let res:number[][]=[]
const foo=(arr: number[], target: number,sum:number,startIndex:number)=>{
if(sum==target){
res.push(Array.from(arr))
return
}
if(sum>target) return
for(let i=startIndex;i<candidates.length;i++){
if(sum+candidates[i]>target) continue
arr.push(candidates[i])
sum+=candidates[i]
foo(arr,target,sum,i)//这里继续从i开始 因为可以重复
sum-=candidates[i]
arr.pop()
}
}
foo([],target,0,0)
return res
};
思考
这道题如果不考虑去重的话是比较简单的,但是要考虑去重的话,需要思考如何去重,自己的想法是利用排序+指向标,小于指向标的话就不进行递归了.文章用的是startIndex,用于去重,同时递归时从i开始,保证了一个元素可以重复使用.
40. 组合总和 II
链接
文章链接
题目链接
第一想法
这道题要求是每个数字只能用一次,所以需要startIndex用于防止一个数字用多次,同时也需要去重,如何去重?详细的在代码中展示
function combinationSum2(candidates: number[], target: number): number[][] {
let res:number[][]=[]
candidates.sort((a,b)=>a-b)//用于去重 关键一步
const foo=(arr:number[],startIndex:number,candidates: number[], target: number,sum:number)=>{
if(sum>target) return //终止
if(sum==target){//终止
res.push(Array.from(arr))
return
}
for(let i=startIndex;i<candidates.length;i++){
if(i>startIndex&&candidates[i]==candidates[i-1]) continue//去重 例如[1,1,2,3],target=3的情况 因为第一个1能出现[1,2]这个结果 所以就不需要第二个1出现[1,2]这个结果 这就需要在本层阻止第二个1进行递归,所以这里的条件为i>startIndex&&candidates[i]==candidates[i-1]用于阻止之后相同的数进入递归
sum+=candidates[i]
arr.push(candidates[i])
foo(arr,i+1,candidates,target,sum)
sum-=candidates[i]//回溯
arr.pop()
}
}
foo([],0,candidates,target,0)
return res
};
看完文章后的想法
文章的想法和我的想法类似,思想就是在同一层去重,附一张图片:
如何在同一层去重就是一个难点,文章用了两种方法进行去重,一个是和我一样的,另一种使用数组去重,数组去重就是用是否使用过,如果是树枝去重就是used[i-1]==true,如果是树层去重的话就是used[i-1]==false,详细解释如这张图:
代码如下:
function combinationSum2(candidates: number[], target: number): number[][] {
let res:number[][]=[]
candidates.sort((a,b)=>a-b)
const foo=(arr:number[],startIndex:number,candidates: number[], target: number,sum:number,used:boolean[])=>{
if(sum>target) return
if(sum==target){
res.push(Array.from(arr))
return
}
for(let i=startIndex;i<candidates.length;i++){
if(candidates[i]==candidates[i-1]&&used[i-1]==false) continue
sum+=candidates[i]
arr.push(candidates[i])
used[i]=true
foo(arr,i+1,candidates,target,sum,used)
used[i]=false
sum-=candidates[i]
arr.pop()
}
}
let used=new Array(candidates.length).fill(false)
foo([],0,candidates,target,0,used)
return res
};
思考
这道题就是考的去重,我认为sort()+startIndex去重是比used去重好的,所占据的空间比较小,虽然used号理解,但是熟练运用的还是startIndex方法.
131. 分割回文串
链接
文章链接
题目链接
第一想法
这道题知道是用回溯法,但是不知道怎么用,所以就没写出来,没啥想法.
看完文章后的想法
寄,确实没想到,其实分割可以抽象出分组,例如这张图:
所以终止条件就很容易看出来了,当index>=str长度时就可以终止了,同时,要确定本层是回文串时才能继续向下层递归,代码如下:
function partition(s: string): string[][] {
let res:string[][]=[]
const foo=(str:string,startIndex:number,arr:string[])=>{
if(startIndex>=str.length){//终止条件
res.push(Array.from(arr))
return
}
for(let i=startIndex;i<str.length;i++){
if(isPalindrome(str,startIndex,i)){ //判断是否是回文串 只有回文串才继续向下递归
let s:string=str.substring(startIndex,i+1)
arr.push(s)
foo(str,i+1,arr)
arr.pop()
}else continue;
}
}
const isPalindrome=(str:string,start:number,end:number)=>{ //判断是否是回文
for(;start<end;start++,end--){
if(str[start]==str[end]) continue
else return false
}
return true
}
foo(s,0,[])
return res
};
思考
这道题难在如何把分割思想转换为分组思想,以及如何模拟分割.这道题如果能想到分组的方法,这道题就能转出来,分割是用startIndex来进行分割的,只有是回文子串才继续递归,所以不好想.
今日总结
今日总共三道题,耗时2.5小时,三道题主要涉及去重以及思想转换,第一道题去重比较简单,第二道题就需要考虑如何去重,第三道题对我来说是最难得,没有想法.看完文章后才恍然大悟,分割问题可以用分组的方法解决.第三道题得多多查看