这道题和前面组合问题的区别是,取的元素可以重复,也就是遍历的时候,同一个元素可以一直取。所以for循环里,逐个添加元素,判断和大于目标时break(否则会一直加)
还是新建二维数组放结果,一维数组放path。输入参数为放结果数组、path、提供的数组、目标值、目前总和sum、startIndex
提前把提供的数组排序,用Arrays.sort() 这样sum超过target就break
递归的时候,每次startIndex都从i开始,不从i+1,这样同一个数字就可以重复
最后回溯的时候用path.removeLast()就行,不需要答案上那种具体的path.remove(path.size() - 1);
和组合总和那道题的区别,本题的难点在于中:集合(数组candidates)有重复元素,但还不能有重复的组合。
这就要去重。包括树枝去重和树层去重。用哪个?用树层去重。
去重逻辑 整理思路看视频:[https://www.bilibili.com/video/BV12V4y1V73A/?vd_source=07371fb33253dfd67e5965271ead821b](https://)
3分50秒--11分50秒部分
为了能用树层去重,判断candidates[i] == candidates[i - 1],提前要将重复的数字都放到一起,所以先进行排序
新建布尔数组used,标记提供的数组某一位数字有没有被用过
candidates[i] == candidates[i - 1]是判断同层或同树一样
candidates[i] == candidates[i - 1] && !used[i - 1]是判断同层有一样,因为同树一样的话used[i - 1]就是true,因为用过
新建长度为...的布尔形式数组 boolean[] used = new boolean[candidates.length];
其实切割问题类似组合问题。
例如对于字符串abcdef:
组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....。
切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....。
在代码里什么是切割线呢?递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。
在递归循环中如何截取子串呢?在for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。判断这个子串是不是回文,如果是回文,就加入
注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1); 传入下一层的起始位置为i + 1。
注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1); 传入下一层的起始位置为i + 1。
用双指针法判断是否是回文
StringBuilder sb = new StringBuilder();
for(int i = startIndex; i < s.length(); i++){
// StringBuilder sb = new StringBuilder();
sb.append(s.charAt(i));
if(check(sb)){
path.add(sb.toString());
backTracing(s, i+1);
path.removeLast();
}
}
StringBuilder sb = new StringBuilder();应该写在for循环外面。因为执行for循环时,每次递加一次,里面就要重新执行一次。如果新建sb放在里面,每次都只拼接一个字母,就会重新初始化。放在外面才能一直拼
if(check(sb)){
......
}
public boolean check(StringBuilder sb){
for(int i = 0; i < sb.length()/2; i++){
if(sb.charAt(i) != sb.charAt(sb.length() - i -1)){
return false;
}
}
return true;
}
这样结果是对的
if(check(sb)){
......
}
public boolean check(StringBuilder sb){
for(int i = 0; i < sb.length()/2; i++){
if(sb.charAt(i) == sb.charAt(sb.length() - i -1)){
return true;
}
}
return false;
}
这样结果是错的
想一下这两个区别是什么?
第一段是一一检查,发现不对应的就返回false
第二段是一一检查,发现对应的就返回true。也就是第二段只要有一个对的就判断为true
但是题目要判断回文,必须全部对才行