计算机小菜鸡求职刷题笔记-回溯算法篇

计算机小菜鸡求职刷题笔记-回溯算法篇

  1. 视频教程:代码随想录labuladong
  2. 可抽象为树型结构:循环+递归
  3. 组合问题就用回溯算法解决

46. 全排列 【交换位置】

  • 总结:列表中交换元素位置Collections.swap()
class Solution {
    List<List<Integer>> res=new ArrayList<>();
    public List<List<Integer>> permute(int[] nums) {
        //回溯法
        List<Integer> list=new ArrayList<>();
        for(int num:nums){
            list.add(num);
        }
        backtrack(0,list);
        return res;
    }

    void backtrack(int x,List<Integer> list){
        if(x==list.size()-1){
            res.add(new ArrayList<>(list));
            return;
        };
        for(int i=x;i<list.size();i++){
            Collections.swap(list,i,x);
            backtrack(x+1,list);
            Collections.swap(list,x,i);
        }
    }
}

39. 组合总和【begin去重】

  • 总结:难点去重!!
    在这里插入图片描述
class Solution {
    List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<Integer> list=new ArrayList<>();
        backtrack(0,candidates,list,target);
        return res;
    }

    void backtrack(int begin, int[] candidates,List<Integer> list,int target){
        if(target==0){
            res.add(new ArrayList<>(list));
            return;
        }
        if(target<0) return;
        
        for(int i=begin;i<candidates.length;i++){
            list.add(candidates[i]);
            backtrack(i,candidates,list,target-candidates[i]);
            list.remove(list.size()-1);

        }

    }
}

47. 全排列 II【排序+used去重】

  • 总结:剪枝去重!!
    在这里插入图片描述

在这里插入图片描述

class Solution {
    List<List<Integer>> res=new ArrayList<>();

    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);

        boolean[] used = new boolean[nums.length];
        List<Integer> list=new ArrayList<>();
        backtrack(list,used,nums);
        return res;
    }

    void backtrack(List<Integer> list,boolean[] used,int[] nums){
        if(list.size()==nums.length){
            res.add(new ArrayList<>(list));
            return;
        }

        for(int i=0;i<nums.length;i++){
            if(used[i]==true) continue;
            if(i>0 && nums[i]==nums[i-1] && used[i-1]==false) continue;

            list.add(nums[i]);
            used[i]=true;
            backtrack(list,used,nums);
            used[i]=false;
            list.remove(list.size()-1);
        }
    }
   
}

40. 组合总和 II 【begin+used去重】

  • 总结:由于输入列表存在重复元素,则利用used列表记录元素是否被使用过;由于最后的结果不用考虑元素的顺序,则利用begin去重。
class Solution {

    // 初步想法采用used列表和begin去重
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<Integer> list = new ArrayList<>();
        boolean[] used = new boolean[candidates.length];
        backtrace(0, candidates, target, list, used);

        return res;

    }

    void backtrace(int begin, int[] candidates, int target, List<Integer> list, boolean[] used){
        if(target<0) return;
        if(target==0){
            res.add(new ArrayList<>(list));
            return;
        }

        for(int i = begin; i < candidates.length; i++){
            if(used[i]==true) continue;
            if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false) continue;

            list.add(candidates[i]);
            target = target - candidates[i];
            used[i] = true;
            backtrace(i+1, candidates, target, list, used);
            used[i] = false;
            target = target + candidates[i];
            list.remove(list.size()-1);            
        }
    }
}

494. 目标和【也可用动态规划求解】

  • 总结:记录当前元素索引,每次均有 “ + ” “+” + " − " "-" "" 两种选择,并将target作为叶子节点,不断更新。
class Solution {

    int ans = 0;
    public int findTargetSumWays(int[] nums, int target) {
        backtrace(0, nums, target);
        return ans;
    }
    void backtrace(int x,int [] nums, int target){
        if(x==nums.length){
            if(target==0){
                ans+=1;
                return;
            }
            else return;
        }

        // +-循环
        target = target + nums[x];
        backtrace(x+1,nums,target);
        target = target - nums[x];

        target = target - nums[x];
        backtrace(x+1,nums,target);
        target = target + nums[x];        
    }
}

216. 组合总和 III 【begin去重】

  • 总结: n n n t a r g e t target target 值,也其他题一样作为叶子节点。
class Solution {

    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<Integer> list = new ArrayList<>();
        backtrace(0, k, n, 1, list);
        return res;

    }

    void backtrace(int x, int k, int n, int begin, List<Integer> list){
        if(n<0) return;
        if(x==k){
            if(n==0){
                res.add(new ArrayList<>(list));
                return;
            }
            else return;
        }

        for(int i=begin;i<10;i++){
            list.add(i);
            n = n - i;
            backtrace(x+1, k, n, i+1, list);
            n = n + i;
            list.remove(list.size()-1);
        }
    }
}

17. 电话号码的字母组合 【号码字母映射 + char->int】

  • 总结:本来觉得很简单,但是发现号码字母映射刚开始不太会初始化…后来知道可 S t r i n g [ 10 ] String[10] String[10] 或者 h a s h M a p hashMap hashMap 解决;其次遇到 c h a r char char i n t int int 的问题,并不能直接 i n t ( c h a r ) int(char) int(char),因为会转化成ASCII码,最后用 c h a r − ′ 0 ′ char - '0' char0 解决。
 //号码字母映射两种方法
 Map<Character, String> phoneMap = new HashMap<Character, String>() {{
            put('2', "abc");
            put('3', "def");
            put('4', "ghi");
            put('5', "jkl");
            put('6', "mno");
            put('7', "pqrs");
            put('8', "tuv");
            put('9', "wxyz");
        }};
 //或者
 String[] alphabet = new String[]{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
class Solution {

     List<String> res = new ArrayList<>();
    String[] alphabet = new String[]{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

    public List<String> letterCombinations(String digits) {
        if(digits.length()==0) return res;
        StringBuffer str = new StringBuffer();
        backtrace(digits, str);
        return res;
    }

    void backtrace(String digits, StringBuffer str) {
        if (str.length() == digits.length()) {
            res.add(str.toString());
            return;
        }

        String digit = alphabet[digits.charAt(str.length())-'0']; //-’0‘ 很重要 由ascii值转为int

        for (int i = 0; i <digit.length(); i++) {
            str.append(digit.charAt(i));
            backtrace(digits, str);
            str.deleteCharAt(str.length() - 1);
        }
    }
}

77. 组合【剪枝】

  • 总结:刚开始只记得用begin去重,但没考虑剪枝,后来对 i i i 的取值加以限制,避免遍历到最后列表元素不足 k k k 个。
class Solution {
    List<List<Integer>> res = new ArrayList<>();

    //begin去重
    public List<List<Integer>> combine(int n, int k) {
        List<Integer> list = new ArrayList<>();
        backtrace(1, n, k, list);
        return res;
    }
    void backtrace(int begin, int n, int k, List<Integer> list){
        if(list.size()==k){
            res.add(new ArrayList<>(list));
            return;
        }
        for(int i=begin; i<=n-(k-list.size()-1); i++){
            list.add(i);
            backtrace(i+1, n, k, list);
            list.remove(list.size()-1);
        }
    }
}

78. 子集【begin去重】

  • 总结:每次选择都是其中的结果
class Solution {

    // begin去重,将’‘作为选择之一,当遇到’‘即为终止
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        List<Integer> list = new ArrayList<>();
        backtrace(0, nums, list);
        return res;
    }

    void backtrace(int begin, int[] nums, List<Integer> list){
        res.add(new ArrayList<>(list));

        for(int i = begin; i<nums.length;i++){
            list.add(nums[i]);
            backtrace(i+1, nums,list);
            list.remove(list.size()-1);
        }

    }
}

90. 子集 II 【begin+used】

  • 总结:同78题类似,融入used去重
class Solution {
    List<List<Integer>> res = new ArrayList<>();

    //used begin去重
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        List<Integer> list = new ArrayList<>();
        boolean[] used = new boolean[nums.length]; 
        backtrace(0, nums, used, list);
        return res;
    }

    void backtrace(int begin, int[] nums, boolean[] used, List<Integer> list){
        res.add(new ArrayList<>(list));

        for(int i = begin; i<nums.length; i++){
            if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false) continue;

            list.add(nums[i]);
            used[i]=true;
            backtrace(i+1, nums,used,list);
            used[i]=false;
            list.remove(list.size()-1);
        }
    }
}

526. 优美的排列 【used】

  • 总结:used记录已使用的元素。
class Solution {
    int count = 0;

    public int countArrangement(int n) {
        boolean[] used = new boolean[n+1];
        backtrace(1,n,used);
        return count;
    }

    void backtrace(int idx, int n, boolean[] used){
        if(idx==n+1){
            count+=1;
            return;
        }

        for(int i=1;i<=n; i++){
            if(used[i]==false&&(i%idx==0||idx%i==0)){
                used[i]=true;
                backtrace(idx+1,n,used);
                used[i]=false;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值