回溯算法经典题,全排列+子集Java

回溯算法经典题,全排列+子集Java什么是排列!什么是组合?排列是有序的,组合是无序的1,2,3 1,3,2 是两种排列,但是只是一种组合。

欢迎大家来到IT世界,在知识的湖畔探索吧!

回溯算法经典题,全排列+子集Java

什么是排列!什么是组合?

排列是有序的,组合是无序的

1,2,3 1,3,2 是两种排列,但是只是一种组合。

回溯算法

void backtrack(结果list, 一个符合条件的结果list(路径list), 原输入数组nums){

}

先判断递归结束条件

if(结果list 的长度和输入数组长度一样){

这个结果有效,把他放入二维结果数组里面

返回

}

遍历输入数组

如果这个数字用过了,就跳过这个循环(不能重复问题)

继续下一个循环,加入别的数字

做回溯递归,改变变量,这是在for循环里面递归

移出最后一个添加的元素;

class Solution {


    List<List<Integer>> res;//结果
    List<Integer> path;//路径
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();//结果
        List<Integer> path = new ArrayList<>();;//路径
        // Arrays.sort(nums); // not necessary
       
        backtrack(res, path, nums);
        return res;
    }
    
    private void backtrack(List<List<Integer>> res, List<Integer> path, int[] nums){
        if(nums.length == path.size()){
            // res.add(path);
            res.add(new ArrayList<>(path));//这里要new, 不然返回的都是空数组,java 是值传递。
            return;
        }

        for(int i = 0; i < nums.length; i++){
            if(path.contains(nums[i])){ //list 有contains 方法。 这里也可以用used[] 数组判断
                continue;
            }
            path.add(nums[i]);
            backtrack(res, path, nums);
            path.remove(path.size() - 1);
        }
    }

}

欢迎大家来到IT世界,在知识的湖畔探索吧!

  • 时间复杂度:O(N×N!)

//递归前后代码是对称操作。

回溯算法经典题,全排列+子集Java

欢迎大家来到IT世界,在知识的湖畔探索吧!class Solution {    public List<List<Integer>> permuteUnique(int[] nums) {    // List<List<Integer>> res;//结果    // List<Integer> path;//路径           List<List<Integer>> res = new ArrayList<>();//结果        List<Integer> path = new ArrayList<>();;//路径        Arrays.sort(nums); //necessary               backtrack(res, path, nums, new boolean[nums.length]);        return res;    }        private void backtrack(List<List<Integer>> res, List<Integer> path, int[] nums, boolean used[]){        if(nums.length == path.size()){            // res.add(path);            res.add(new ArrayList<>(path));//这里要new, 不然返回的都是空数组,java 是值传递。            return;        }        for(int i = 0; i < nums.length; i++){                        if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;            // if(path.contains(nums[i])){ //list 有contains 方法。 这里也可以用used[] 数组判断            //     continue;            // }            path.add(nums[i]);            used[i] = true;            backtrack(res, path, nums, used);            used[i] = !used[i];            path.remove(path.size() - 1);                    }    }}

去重判断:

if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i – 1]) continue;

回溯算法经典题,全排列+子集Java

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        // Arrays.sort(nums);//先排序
        backtrack(res, path, nums, 0);
        return res;


    }
    private void backtrack(List<List<Integer>> res, List<Integer> path, int[] nums, int start){
        if(start > nums.length){
            return;
        }
        res.add(new ArrayList<>(path));//加入结果,先加入一个空集

        for(int i = start; i< nums.length; i++){
            path.add(nums[i]);
            //回溯加另一个分支(自己画一个树形结构,排列组合),回溯做另一个选择
            backtrack(res, path, nums, i + 1); // 注意从i+1开始,元素不重复取
            //撤销选择
            path.remove(path.size()-1);//移除最后一位元素,上一次加入数组的(画出树形图好理解)
        }
    }


}

组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

写回溯算法的时候,for就要从startIndex开始,而不是从0开始!

—-参考《代码随想录》

回溯算法经典题,全排列+子集Java

再做回溯时候加两行代码就可以,跳过重复元素。

排序, i 和 i-1 位置元素一样,跳过i 位置

if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates

欢迎大家来到IT世界,在知识的湖畔探索吧!class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {


        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        Arrays.sort(nums);//先排序,不然这样的没法去重,[4,4,4,1,4]
        backtrack(res, path, nums, 0);
        return res;


    }
    private void backtrack(List<List<Integer>> res, List<Integer> path, int[] nums, int start){
        if(start > nums.length){
            return;
        }
        res.add(new ArrayList<>(path));//加入结果,先加入一个空集

        for(int i = start; i< nums.length; i++){
            //去重
            if(i > start && nums[i] == nums[i-1]){
                continue;
            }


            path.add(nums[i]);
            //回溯加另一个分支(自己画一个树形结构,排列组合),回溯做另一个选择
            backtrack(res, path, nums, i + 1); // 注意从i+1开始,元素不重复取
            //撤销选择
            path.remove(path.size()-1);//移除最后一位元素,上一次加入数组的(画出树形图好理解)
        }
    }


}
 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/37338.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信