回溯算法

剑指 Offer 38. 字符串的排列
注意:并没有剪枝,是利用set去的重。

class Solution {
    public String[] permutation(String s) {
        char c[] = s.toCharArray();
        Set<String> res = new HashSet<>();
        backtrack(c,"",new boolean[c.length],res);
        return res.toArray(new String[res.size()]);
    }
    private void backtrack(char[] chars,String temp,boolean[] visited,Set<String> res){
        if(chars.length == temp.length()){
            res.add(temp);
            return;
        }
        for(int i=0;i<chars.length;++i){
            if(visited[i])
                continue;
            visited[i] = true;
            backtrack(chars,temp+chars[i],visited,res);
            visited[i] = false;
        }
    }
}

回溯算法模板:

private void backtrack("原始参数") {
    //终止条件(递归必须要有终止条件)
    if ("终止条件") {
        //一些逻辑操作(可有可无,视情况而定)
        return;
    }
    for (int i = "for循环开始的参数"; i < "for循环结束的参数"; i++) {
        //一些逻辑操作(可有可无,视情况而定)
        //做出选择
        //递归
        backtrack("新的参数");
        //一些逻辑操作(可有可无,视情况而定)
        //撤销选择
    }
}

473. 火柴拼正方形
思路:理解为四叉树并不合适,但是仍然利用四叉树的深度递归解决

class Solution {
    public boolean makesquare(int[] matchsticks) {
        int sum = 0;
        for(int i:matchsticks){
            sum+=i;
        }
        if((sum&3 )!= 0||sum == 0) return false;
        return dfs(0,matchsticks,sum>>2,new int[4]);
    }

    public   boolean dfs(int index,int sticks[],int target,int size[]){
        if(index == sticks.length){
            if(size[0] == size[1] && size[1] == size[2] && size[2] == size[3]) return true;
           return false;
        }
        for(int i=0;i<size.length;++i){
            if(size[i] + sticks[index]>target)
                continue;
            size[i]+=sticks[index];
            if(dfs(index+1,sticks,target,size)){
                return true;
            }else{
                size[i]-=sticks[index];
            }
        }
        return false;
     }
}

90. 子集 II
1.每个父节点 都有一个独立的set 保存子节点取得元素,用于去重
在这里插入图片描述

class Solution {
     List<List<Integer>> res ;
     List<Integer> path;
    
    public List<List<Integer>> subsetsWithDup(int[] nums) {
       res = new ArrayList<>();
        path = new ArrayList<>();
     
      Arrays.sort(nums);
        dfs(nums,0);
        return res;
    }
    private void dfs(int[] nums,int start){
        res.add(new ArrayList<>(path));
         Set<Integer> set = new HashSet<>();
        for(int i=start;i<nums.length;++i){
            if(set.contains(nums[i])) continue;
            path.add(nums[i]);
            set.add(nums[i]);
            dfs(nums,i+1);
            path.remove(path.size()-1);  
        }
    }
}

官方解法
回溯的时候,用过的元素 visited[i]会变为false,同一层没有用过的也是false,由于数组排过序,所以
如果当前元素和前一个元素相同,而且前一个元素visited[i]为false,说明前一个相同的元素在当前层已经被用过了

class Solution {
    private List<List<Integer>> ans;
    private List<Integer> path;

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        ans = new ArrayList<>();
        path = new ArrayList<>();
        // 首先排序,让相同的两个元素排到一起去,便于去重
        Arrays.sort(nums);
        int n = nums.length;
        // 使用 visited 数组来记录哪一个元素在当前路径中被使用了
        boolean[] visited = new boolean[n];
        // 开始回溯
        backtrace(nums, 0, visited, n);
        return ans;
    }

    private void backtrace(int[] nums, int start, boolean[] visited, int n) {
        // 首先加入当前路径
        ans.add(new ArrayList<>(path));
        // 从 start 开始遍历每一个元素,尝试加入路径中
        for (int i = start; i < n; ++i) {
            // 如果当前元素和前一个元素相同,而且前一个元素没有被访问,说明前一个相同的元素在当前层已经被用过了
            if (i > 0 && nums[i - 1] == nums[i] && !visited[i - 1]) continue;
            // 记录下来,用过了当前的元素
            visited[i] = true;
            path.add(nums[i]); // 放到路径中
            backtrace(nums, i + 1, visited, n); // 向下一个递归
            visited[i] = false; // 回溯
            path.remove(path.size() - 1);
        }
    }
}

牛客:括号生成
给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合。
例如,给出n=3,解集为:
“((()))”, “(()())”, “(())()”, “()()()”, “()(())”,

 public ArrayList<String> generateParenthesis (int n) {
        // write code here
        ArrayList<String> res = new ArrayList<>();
        func(res,"",n,n);
        return res;
    }
    private void func( List<String> res,String s,int l,int r){
        if(l ==0 && r==0){
            res.add(s);
            return ;
        }
        if(l<0 ) return ;
        if(r<l) return ;
        
        func(res,s+"(",l-1,r);
        func(res,s+")",l,r-1);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值