93. 复原 IP 地址
链接
文章链接
题目链接
第一想法
这道题第一时间没想到,后来思考了一下,想到了昨天做的分割回文串,然后就有了思路,这道题我感觉难在条件的判断上,总共有以下几个需要进行判断:
一.终止条件是什么:
- 和回文串一样如果分割位置startIndex大于等于字符串的长度就终止
- 如果存储片段的arr.length>4,说明一定不能组成ip
二.不符合规则的ip有哪几种
- 单个字段长度大于3的就不符合
- 如果长度大于1但是含有前导0的
- 单个字段数值大于255的
代码如下:
function restoreIpAddresses(s: string): string[] {
let res:string[]=[]
const foo=(arr:string[],startIndex:number,s:string)=>{
if(arr.length>4) return
if(startIndex>=s.length){
if(arr.length===4) res.push(arr.join("."))
return
}
for(let i=startIndex;i<s.length;i++){
if(i-startIndex>=3) continue//单个字段长度大于3的就不符合
let str:string=s.substring(startIndex,i+1)
if(str.length>1&&str[0]=="0") continue//长度大于1但是含有前导0的
if(Number(str)>255) continue//单个字段数值大于255的
arr.push(str)
foo(arr,i+1,s)
arr.pop()//回溯
}
}
foo([],0,s)
return res
};
看完文章后的想法
文章中用的思路和我的是一样的,但是文章是直接用的是字符串,而我用的是数组,本质是一样的,想看字符串写法的可以去代码随想录中查看,我上面的代码是可以优化的,因为i-startIndex>=3之后是肯定不成立的,所以可以把循环条件改一下:
for(let i=startIndex;i<Math.min(s.length,startIndex+3);i++){//这里进行缩减一下
let str:string=s.substring(startIndex,i+1)
if(str.length>1&&str[0]=="0") continue
if(Number(str)>255) continue
arr.push(str)
foo(arr,i+1,s)
arr.pop()
}
思考
如果昨天没有做分割回文串的话,今天这道题应该是很难想到的,由于昨天做过回文串,所以这道题就比较容易好像的,其中比较难的是如何去除不符合条件ip地址,罗列一下就很清晰了.
78. 子集
链接
文章链接
题目链接
第一想法
这道题看到的时候觉得是简单的,因为只需要把终止条件去掉,因为这回需要的是过程量,不只是结果量,代码如下:
function subsets(nums: number[]): number[][] {
let res:number[][]=[]
const foo=(nums:number[],arr:number[],startIndex:number)=>{
res.push(Array.from(arr))
for(let i=startIndex;i<nums.length;i++){
arr.push(nums[i])
foo(nums,arr,i+1)
arr.pop()
}
}
foo(nums,[],0)
return res
};
看完文章后的想法
文章把这道题讲的很通透,如果把分组、分割、子集问题看成一棵树的话,分组和分割都是收集叶子节点,而子集问题是收集所有的节点,例如这张图:
为了防止一个数用了多次,所以还是用startIndex来控制开始遍历的位置,这道题文章中和我写的是一样的,这里就不放代码了,有兴趣的可以查看代码随想录.
思考
这道题其实就是一道标准的回溯模版题,不一样的是以前做的分割和分组的题都是收集叶子节点,而子集收集的是所有节点而已,就这一个差别而已.
90. 子集 II
链接
文章链接
题目链接
第一想法
看到之后知道是要树层去重的,由于之前做过组合总和II这道题,所以这道题的去重很容易就写出来了
function subsetsWithDup(nums: number[]): number[][] {
let res:number[][]=[]
const foo=(arr:number[],nums:number[],startIndex:number)=>{
res.push(arr.slice())
for(let i=startIndex;i<nums.length;i++){
if(i>startIndex&&nums[i]==nums[i-1]) continue//树层去重 如果元素相同的话 当前元素和前一个相同的元素肯定会产生结果,所以当前元素就不用继续递归了
arr.push(nums[i])
foo(arr,nums,i+1)
arr.pop()
}
}
nums.sort((a,b)=>a-b)//对于去重关键的一步
foo([],nums,0)
return res
};
看完文章后的想法
文章也是说和组合去重II是一样的,所以还是用used数组和我刚刚写的两种方法来,这里就不多加叙述了,文章和我写的是类似的.
今日总结
今天总共三道题,一道分割两道子集,个人觉得分割还是比较难做的,子集感觉套模板+去重就可以秒杀大部分题了,今日耗时2小时,今天比较简单.