文章目录
- LeetCode 93.复原IP地址
- 题目讲解
- 思路
- LeetCode 78.子集
- 题目讲解
- 思路
- LeetCode 90.子集II
- 题目讲解
- 难点
- 总结
LeetCode 93.复原IP地址
题目讲解
思路
- 递归参数
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
本题我们还需要一个变量pointNum,记录添加逗点的数量。
- 递归终止条件
终止条件和131.分割回文串 (opens new
window)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
然后验证一下第四段是否合法,如果合法就加入到结果集里
- 单层搜索的逻辑
在131.分割回文串 (opens new window)中已经讲过在循环遍历中如何截取子串。
在for (int i = startIndex; i < s.size(); i++)循环中 [startIndex, i]
这个区间就是截取的子串,需要判断这个子串是否合法。如果合法就在字符串后面加上符号.表示已经分割。
如果不合法就结束本层循环,如图中剪掉的分支:
然后就是递归和回溯的过程:
递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符.),同时记录分割符的数量pointNum 要
+1。回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要-1。
class Solution {
List<String> result = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
if( s.length()>12)return result;
backtrack(s,0,0);
return result;
}
public void backtrack(String s,int StartIndex,int pointNum)
{
if(pointNum ==3)
{
if( isvalid( s,StartIndex,s.length()-1))
{
result.add(s);
}
return;
}
for(int i=StartIndex;i<s.length();i++)
{
if(isvalid(s,StartIndex,i))
{
s= s.substring(0,i+1) +"."+s.substring(i+1);
pointNum++;
backtrack(s,i+2,pointNum);
pointNum--;
s= s.substring(0,i+1)+s.substring(i+2);
}else
{
break;
}
}
}
public boolean isvalid(String s, int start ,
int end)
{
if( start>end ) return false;
if( s.charAt(start)=='0'&& start!= end)
{return false;}
int num=0;
for(int i=start;i<=end;i++)
{
if(s.charAt(i) >'9'|| s.charAt(i)<'0')
return false;
num=num*10+(s.charAt(i)-'0');
if(num>255) return false;
}
return true;
}
}
LeetCode 78.子集
题目讲解
思路
- 递归函数参数
全局变量数组path为子集收集元素,二维数组result存放子集组合。(也可以放到递归函数参数里)
递归函数参数在上面讲到了,需要startIndex。
- 递归终止条件
其实可以不需要加终止条件,因为startIndex >= nums.size(),本层for循环本来也结束了。
- 单层搜索
求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树
class Solution {
LinkedList<Integer> path = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
subsetsHelper(nums,0);
return result;
}
public void subsetsHelper(int[] nums, int startIndex)
{
result.add(new ArrayList<>(path));
for(int i=startIndex;i<nums.length;i++)
{
path.add(nums[i]);
subsetsHelper(nums,i+1);
path.removeLast();
}
}
}
LeetCode 90.子集II
题目讲解
难点
结合了前面的子集 和组合总和 的知识点 要晓得树层去重
还会用到used数组,
如果要是全排列的话,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。
class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
boolean[] used;
public List<List<Integer>> subsetsWithDup(int[] nums) {
if( nums.length==0)
{ result.add(path);
return result;
}
used= new boolean[nums.length];
Arrays.sort(nums);
backtrack(nums,0);
return result;
}
public void backtrack(int[]nums, int StartIndex)
{
result.add(new ArrayList<>(path));
if( StartIndex>nums.length)
{
return;
}
for( int i =StartIndex;i<nums.length;i++)
{
if(i>0 && nums[i]== nums[i-1] && !used[i-1])
{
continue;
}
path.add(nums[i]);
used[i]= true;
backtrack(nums,i+1);
path.removeLast();
used[i]= false;
}
}
}
总结
大多数优秀的程序员从事编程工作,不是因为期望获得报酬或得到公众的称赞,而是因为编程是件有趣的事儿