回溯算法part03 算法

回溯算法part03 算法

今日任务

● 39. 组合总和
● 40.组合总和II
● 131.分割回文串

1.leetcode 39. 组合总和

https://leetcode.cn/problems/combination-sum/

class Solution {
    List<List<Integer>> result=new ArrayList<>();
    List<Integer> path=new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backtracing(candidates,target,0,0);
        return result;
    }
    public void backtracing(int[] c,int target,int sum,int index){
        //大于就直接退出吧,不用再添加了
        if(sum>target){
            return;
        }
        if(sum==target){
            //new成一维的添加进去
            result.add(new ArrayList<>(path));
            return;
        }
        //学会画图理解
        //横向遍历for,横向数组元素为该起点+1往后
        //纵向回溯得深度,纵向得数组元素为该起点往后
        //需要注意的点是我们要标记记录此时遍历到的下标,保存下次使用,可以作为参数或者在该函数的全局变量,但是不能作为局部变量,局部变量出保护域就保存不了
        for(int i=index;i<c.length;i++){//画的树的宽度
            //一维集合添加进去的元素不用new ,直接添加进去即可
            //因为添加了,就是同个类型加进去了
            //将元素添加进一维集合中
            path.add(c[i]);
            //累加
            sum+=c[i];
            //往深度纵向进行回溯,不是i+1,而是原i
            backtracing(c,target,sum,i);
            //函数执行结束的话
            //累减回溯恢复
            sum-=c[i];
            path.removeLast();
        }
    }
}

2.leetcode 40.组合总和II

https://leetcode.cn/problems/combination-sum-ii/description/

import java.util.*;
class Solution {
    List<List<Integer>> result=new ArrayList<>();
    List<Integer> path=new ArrayList<>();

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        //别忘了将数组进行排i序
        Arrays.sort(candidates);//改变得是原数组//对原数组进行排序
        //布尔类型的数组
        boolean[] used=new boolean[candidates.length];//不复制就默认为0
        backtracing(candidates,target,0,0,used);

        //去重法一
        //Set> set = new HashSet<>(result);
        //return new ArrayList<>(set);

        //去重法二
        return result;
    }
    public void backtracing(int[] c,int target,int sum,int index,boolean[] used){
        if(sum>target){
            return;
        }
        if(sum==target){
            //加进二维数组中
            //这样得到得一维集合会出现完全重复,也就是低位置得元素和后面的又组成一起
            /**
            1.低位置的元素和后面的又组成一起(能理解)
            比如:原数组[1,1,2,5,6,7,10]
            第一个元素[1,2,5]
            第二个元素[1,2,5]
            如何解决:
            法一:直接将得到的二维集合进行去重
            将ArrayList二维集合放进HashSet>中进行去重,但是结果会超出内存限制

            法二:在收集result之前就不去收集重复的节点
            如何判断同一树层上元素(相同的元素)是否使用过了呢。
            如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false
            就说明:前一个树枝,使用了candidates[i - 1],
            也就是说同一树层使用过candidates[i - 1]。
            此时for循环里就应该做continue的操作。

            2.为什么会出现一维集合元素顺序不一样的相等
            比如:[1,2,5]和[1,5,2]和[2,1,5]和[5,1,2]
            我不是已经对数组进行排序了吗
            而且控制纵向的不再重复index+1(写错了,得是i+1)
             */
            result.add(new ArrayList<>(path));
            return;
        }
        for(int i=index;i<c.length;i++){//横向遍历得宽度
            //user[i-1]==true,说明同一树枝c[i-1]使用过(纵向)//还没有进行回溯清除
            //user[i-1]=false,说明同一树层c[i-1]使用过(横向)//得跳过到下一树层,不要重复相同元素节点
            //对同一树层使用过的元素进行跳过
            if(i>0&&c[i]==c[i-1]&&used[i-1]==false){
                continue;
            }
            //加进一维数组中
            path.add(c[i]);
            //累加
            sum+=c[i];
            //标记用过
            used[i]=true;
            //纵向递归
            backtracing(c,target,sum,i+1,used);//因为不能重复,不像39题
            //回溯
            sum-=c[i];
            path.removeLast();
            used[i]=false;
        }
    }
}

3.leetcode 131.分割回文串

https://leetcode.cn/problems/palindrome-partitioning/

class Solution {
    List<List<String>> result=new ArrayList<>();
    List<String> path=new ArrayList<>();
    public List<List<String>> partition(String s) {
        backtracing(s,0);
        return result;
    }
    public void backtracing(String s,int index){
        //当现在遍历到的位置是字符串长度时
        if(index>=s.length()){
            //将一维集合放进二维集合中,是不是回文串我们在单层逻辑里面去判断
            result.add(new ArrayList<>(path));
            return;
        }
        for(int i=index;i<s.length();i++){//横向遍历
            //如何切割
            //如果是回文串就记录
            if(isHuiWen(s,index,i)){
                String str=s.substring(index,i+1);
                path.add(str);
            }else{
                //不是的话就下一个i//横向宽度
                continue;
            }
            //纵向深度
            backtracing(s,i+1);//不重复
            //回溯
            path.removeLast();
        }
    }
    //判断是不是回文串(文串 是正着读和反着读都一样的字符串)
    //那就是aba也算是
    public boolean isHuiWen(String s,int startIndex,int end){
        //将要判断的字符串传进来,用前后两个指针,每次都想中间遍历,要是前指针指向的元素=后指针指向的元素,那么就证明这两个元素相等
        for(int i=startIndex,j=end;i<j;i++,j--){
            //i=j时,没有意义,指针都指向同一个元素,肯定是相等的
            if(s.charAt(i)!=s.charAt(j)){
                return false;
            }
        }
        return true;
    }
}

你可能感兴趣的:(算法)