概述
算法–回溯算法
回溯问题一般常见两种操作是去重
和剪枝
。
(1)去重是为了避免出现重复的结果。
(2)剪枝是为了当出现明显的不符合题目的要求时,跳过这一元素,节省时间。
组合总数
class Solution {
List<List<Integer>> res = new ArrayList<>();
private void dfs(int[] candidates,int target,List<Integer> temp,int index)
{
if(target==0)
{
res.add(new ArrayList<>(temp));
return ;
}
for(int i=index;i<candidates.length;i++){
if(i!=index&&candidates[i]==candidates[i-1])
continue;//去重
if(target<candidates[i])
break;//剪枝
temp.add(candidates[i]);
dfs(candidates,target-candidates[i],temp,i+1);
temp.remove(temp.size()-1);
}
}
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates,target,new ArrayList<>(),0);
return res;
}
}
为了方便处理重复问题,首先对数组进行排序。确保重复的数组元素相邻。
Arrays.sort(candidates);
在回溯函数中,进行去重操作。
if(i!=index&&candidates[i]==candidates[i-1])
continue;
四数之和
class Solution {
List<List<Integer>> res = new ArrayList();
boolean []vis;
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
vis = new boolean[nums.length];
backTracking(nums,new ArrayList<Integer>(),target,vis,0);
return res;
}
private void backTracking(int[] nums,List<Integer> temp,int target,boolean[] vis,int index){
if(temp.size()==4&&target==0){
res.add(new ArrayList<>(temp));
return;
}
else if(temp.size()==4){
return;
}
for(int i=index;i<nums.length;i++){
if(i>0&&nums[i]==nums[i-1]&&!vis[i-1]){//去重
continue;
}
if(temp.size()==3&&target-nums[i]!=0){//剪枝条(节省时间)
continue;
}
temp.add(nums[i]);
vis[i] = true;
backTracking(nums,temp,target-nums[i],vis,i+1);
vis[i] = false;
temp.remove(temp.size()-1);
}
}
}
与上一个问题组合总数
类似,都是组合数字求和问题,不同点在于四数之和限制了结果的个数只能是4个数字之和。
新增添了一个布尔型数组vis来判断当前元素是否被访问过。去重操作如下:
if(i>0&&nums[i]==nums[i-1]&&!vis[i-1]){//去重
continue;
}
nums[i]==nums[i-1]&&vis[i-1]==false,代表当前元素与之前一个元素相等,且前一个元素本次回溯未被访问。
全排列II
class Solution {
List<List<Integer>> res = new ArrayList<>();
boolean []vis;
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
vis = new boolean[nums.length];
backTracking(nums,new ArrayList<>(),0,vis);
return res;
}
private void backTracking(int[] nums,List<Integer> temp,int index,boolean[] vis){
if(temp.size()==nums.length){
res.add(new ArrayList<>(temp));
return;
}
for(int i=0;i<nums.length;i++){
if(vis[i]||(i>0&&nums[i]==nums[i-1]&&!vis[i-1])){
continue;
}
temp.add(nums[i]);
vis[i] = true;
backTracking(nums,temp,index+1,vis);
temp.remove(temp.size()-1);
vis[i] = false;
}
}
}
与上一个问题相比,去重多了一个判断条件,判断当前元素是否被访问过。因为是排列问题,注重排列顺序,每次回溯都是从数组的一个元素开始遍历,而求和问题则可以从前一个元素开始遍历数组。
最后
以上就是伶俐棉花糖为你收集整理的算法--回溯算法算法–回溯算法的全部内容,希望文章能够帮你解决算法--回溯算法算法–回溯算法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复