1.本题是一个经典的回溯算法题目,怎么辨别题解需要使用回溯算法呢?
回溯法,一般可以解决如下几种问题:
-
组合问题:N个数里面按一定规则找出k个数的集合
-
切割问题:一个字符串按一定规则有几种切割方式
-
子集问题:一个N个数的集合里有多少符合条件的子集
-
排列问题:N个数按一定规则全排列,有几种排列方式
-
棋盘问题:N皇后,解数独等等
2.回溯法模板
回溯三部曲:
(1)返回值以及参数
返回值一般为void。再来看一下参数,因为回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数
(2)回溯函数终止条件
什么时候达到了终止条件,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归
(3)回溯搜索的遍历过程。
for循环是横向遍历可以理解一个节点有多少个孩子,这个for循环就执行多少次
backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
总结回溯算法模板如下:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
3.代码
class Solution {
List<List<Integer>> list2=new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if(candidates==null || candidates.length==0){
return list2;
}
List<Integer> path=new ArrayList<>();
boolean[] used=new boolean[candidates.length];
Arrays.sort(candidates);
dfs(candidates,0,0,path,target,used);
return list2;
}
void dfs(int[] candidates,int start,int sum,List<Integer> path,int target,boolean[] used){
if(sum==target){//如果sum等于我们要求的和就将path添加到list2
list2.add(new ArrayList<Integer>(path));
return;
}
//剪枝3,sum+candidates[i]<=target,当sum已经大于等于目标值,后面就不用看了
//剪枝4,i=start,123和132是一个答案,后面的132要去掉,通过start实现,因为下一层只能比上一层数据更大
for(int i=start;i<candidates.length&&sum+candidates[i]<=target;i++){//当sum+当前数据大于等于目标数就结束循环
if(used[i]==true){//剪枝1,因为每个元素只能用一次
continue;
}
if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false){//剪枝2,因为不能包含重复的
continue;
# 更多:Java进阶核心知识集
包含:JVM,JAVA集合,网络,JAVA多线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等
![image](https://img-blog.csdnimg.cn/img_convert/dc0ae7dc9336da76e645a74b4f97a871.webp?x-oss-process=image/format,png)
# 高效学习视频
g原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等
[外链图片转存中...(img-YSBUsrh6-1718902669519)]
# 高效学习视频