算法-回溯-20230508

回溯模板

private void backTracking(参数) {
        if (终止条件) {
            保存结果等处理
            return;
        }
        for (int i = start; i <= end; i++) { // 循环
            list.add(i); // 增加参数
            backTracking(参数);
            list.remove(list.size() - 1); // 回溯之后弹出
        }
    }

1.组合

class Solution {
   public List<List<Integer>> combine(int n, int k) {
       // 回溯
        List<List<Integer>> result = new ArrayList<>();
        backTracking(new ArrayList<>(), 1, n, k, result);
        return result;
    }
    private void backTracking(List<Integer> list, int start, int end, int k, List<List<Integer>> result ) {
        if (list.size() == k) {
            result.add(new ArrayList<>(list));
            return;
        }
        for (int i = start; i <= end; i++) {
            list.add(i);
            backTracking(list, i+1, end, k, result);
            list.remove(list.size() - 1);
        }
    }
}

2. 组合总和

class Solution {
    private List<List<Integer>> resultList = new ArrayList<>();
    private int sum = 0;
    private LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        backTracking(1,k,n);
        return resultList;
    }

    private void backTracking(int start, int k, int n) {
        if (sum > n || path.size() > k) {
            return;
        }
        if (sum ==n && path.size() == k) {
            resultList.add(new ArrayList<>(path));
            return;
        }
        for (int i = start;  i< 10-(k-path.size()) +1; i++) {
            sum += i;
            path.add(i);
            backTracking(i+1, k, n);
            path.removeLast();
            sum-=i;
        }
    }
}

3.电话号组合

class Solution {
     private List<String> result = new ArrayList<>();
    private StringBuilder stringBuilder = new StringBuilder();
    private Map<Character, String[]> keyDigitsMap = new HashMap<>();
    {
        keyDigitsMap.put('2', new String[]{"a", "b", "c"});
        keyDigitsMap.put('3', new String[]{"d", "e", "f"});
        keyDigitsMap.put('4', new String[]{"g", "h", "i"});
        keyDigitsMap.put('5', new String[]{"j", "k", "l"});
        keyDigitsMap.put('6', new String[]{"m", "n", "o"});
        keyDigitsMap.put('7', new String[]{"p", "q", "r", "s"});
        keyDigitsMap.put('8', new String[]{"t", "u", "v"});
        keyDigitsMap.put('9', new String[]{"w", "x", "y", "z"});
    }

    public List<String> letterCombinations(String digits) {
        if (digits == null || digits.length() <=0) {
            return result;
        }
        backTracing(digits, 0);
        return result;
    }

    private void backTracing(String digits, int start) {
       if (stringBuilder.length() == digits.length()) {
            result.add(stringBuilder.toString());
            return;
        }
          String[] strings = keyDigitsMap.get(digits.charAt(start));
            for (int j = 0; j < strings.length; j++) {
                stringBuilder.append(strings[j]);
                backTracing(digits, start + 1);
                stringBuilder.deleteCharAt(stringBuilder.length()-1);
            }
    }
}

4. 组合之和,字段无限使用

回溯一定是一进一出的

class Solution {
    private LinkedList<Integer> list = new LinkedList<>();
    private List<List<Integer>> result = new ArrayList<>();
    private int sum = 0;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backTracking(candidates, 0, target);
        return result;
    }

    private void backTracking(int[] candidates, int index, int target) {
        if (sum == target) {
            result.add(new ArrayList<>(list));
            return;
        }
        if (sum > target) {
            return;
        }
        for (int i = index; i< candidates.length; i++) {
            sum += candidates[i];
            list.add(candidates[i]);
            if (sum < target){
                backTracking(candidates, i, target);
            }else {
                backTracking(candidates, i + 1, target);
            }
            Integer integer = list.removeLast();
            sum -= integer;
        }
    }
}

5. 组合总和2,结果集不能有重复数组

usesd数组,得好好理解

class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();
    private int sum = 0;
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        boolean[] used = new boolean[candidates.length];
        backTracking(candidates, target, 0, used);
        return result;
    }

    private void backTracking(int[] candidates, int target, int start, boolean[] used) {
        if (sum == target) {
            result.add(new ArrayList<>(list));
            return;
        }

        for (int i = start; i< candidates.length && sum + candidates[i] <= target; i++) {
            if ( i >0 && !used[i - 1] && candidates[i-1] == candidates[i]) {
                continue;
            }
            sum += candidates[i];
            list.add(candidates[i]);
            used[i] = true;
            backTracking(candidates, target, i + 1, used);
            used[i] = false;
            sum -= candidates[i];
            list.removeLast();
        }
    }
}

6. 切割字符串, === 组合

看了半天,真复杂

class Solution {
    List<List<String>> result = new ArrayList<>();
    LinkedList<String> lists = new LinkedList<>();
    public List<List<String>> partition(String s) {
        backTracking (s,  0);
        return result;
    }

    private void backTracking(String s, int start) {
        if (start == s.length()) {
            result.add(new ArrayList<>(lists));
            return;
        }

        for (int i =start; i < s.length(); i++) {
            if (!checkPalindrome(s, start, i+1)) {
                continue;
            }
            lists.add(s.substring(start, i + 1));
            backTracking(s, i + 1);
            lists.removeLast();
        }
    }

    private boolean checkPalindrome(String s, int start, int i) {
        i = i -1;
        while (start < i) {
            if (s.charAt(start) == s.charAt(i)) {
                start++;
                i --;
            }else {
                return false;
            }
        }
        return true;
    }
}

7. 切割ip

缝缝补补

class Solution {
     private List<String> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();

    public List<String> restoreIpAddresses(String s) {
        // 切割,4位数
        backTracking(s, 0);
        return result;
    }

    private void backTracking(String s, int start) {
        if (list.size() > 4) {
            return;
        }
        if (start >= s.length()) {
            if (list.size() == 4) {
                result.add(list.stream().map(String::valueOf).collect(Collectors.joining(".")));
            }
            return;
        }
        for (int i = start; i< s.length(); i++) {
            if (i - start > 3 || s.charAt(start) == '0' && i > start) {
                break;
            }
            if ( 255>=Integer.valueOf(s.substring(start, i+1)) && 0 <= Integer.valueOf(s.substring(start, i+1))) {
                list.add(Integer.valueOf(s.substring(start, i+1)));
            }else {
                continue;
            }
            backTracking(s, i + 1);
            list.removeLast();
        }

    }
}

8.数组的子数组

class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();
    public List<List<Integer>> subsets(int[] nums) {
        backTracking(nums, 0);
        return result;
    }

    private void backTracking(int[] nums, int start) {
        result.add(new ArrayList<>(list));
        for (int i =start; i< nums.length; i++) {
            list.add(nums[i]);
            backTracking(nums, i+1);
            list.removeLast();
        }
    }
    
}

9. 数组的子数组,不能重复,层级去重

class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.sort(nums);
        backTracking(nums, 0, used);
        return result;
    }

    private void backTracking(int[] nums, int start, boolean[] used) {
        
        result.add(new ArrayList<>(list));

        for (int i =start; i< nums.length; i++) {
            if (i > 0 && nums[i] == nums[i-1] && !used[i - 1] ) {
                continue;
            }
            list.add(nums[i]);
            used[i] = true;
            backTracking(nums, i+1, used);
            used[i] = false;
            list.removeLast();
        }
    }
}

10.数组的递增子数组

剪枝!!!,同父节点下不重复

class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backTracking(nums, 0);
        return result;
    }

    private void backTracking(int[] nums, int start) {
        if (list.size() > 1) {
            result.add(new ArrayList<>(list));
        }
        int [] used = new int[201];
        for (int i = start; i < nums.length;i++) {
            if (!list.isEmpty() && nums[i] < list.getLast()) {
                continue;
            }
            if (used[nums[i] + 100] == 1) {
                continue;
            }
            list.add(nums[i]);
            used[nums[i]+100] = 1;
            backTracking(nums, i +1);
            list.removeLast();
        }
    }
}

11. 全排列

每次都从0开始遍历,单树每个元素使用一次。

private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();

    public List<List<Integer>> permute(int[] nums) {
        boolean[] used = new boolean[nums.length];
        backTracking(nums, used);
        return result;
    }

    private void backTracking(int[] nums,  boolean[] used) {
        if (list.size() == nums.length) {
            result.add(new ArrayList<>(list));
            return;
        }
        for (int j = 0; j < nums.length; j++) {
            if (used[j]) {
                continue;
            }
            list.add(nums[j]);
            used[j] = true;
            backTracking(nums, used);
            list.removeLast();
            used[j] = false;
        }
    }

12.全排列2,返回不重复的

去重啊,剪枝啊。同层值相同的,并且前一个节点使用过,则剪枝

class Solution {

    private List<List<Integer>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();

    public List<List<Integer>> permute(int[] nums) {

        boolean[] used = new boolean[nums.length];
        Arrays.sort(nums);
        backTracking(nums, used);
        return result;
    }

    private void backTracking(int[] nums, boolean[] used) {
        if (list.size() == nums.length) {
            result.add(new ArrayList<>(list));
        }
        for (int i = 0; i< nums.length; i++) {
            if(used[i]) {
                continue;
            }
            if(i > 0 && !used[i-1] && nums[i] == nums[i-1]) {
                continue;
            }
            list.add(nums[i]);
            used[i] = true;
            backTracking(nums, used);
            list.removeLast();
            used[i] = false;
        }
    }
}

13. n皇后,回溯,手写

class Solution {
    private List<List<String>> result = new ArrayList<>();
    private LinkedList<Integer> list = new LinkedList<>();
    public List<List<String>> solveNQueens(int n) {

        backTracking(n);
        return result;
    }

    private void backTracking(int n) {
        if (list.size() == n ) {
            result.add(getResult(list));
            return;
        }
        for (int i =0 ; i < n; i ++) {
            // 竖
            if (list.contains(i)) {
                continue;
            }
            // 斜对角
            if (!list.isEmpty()) {
                int size = list.size();
                boolean flag = false;
                for (int j = 0; j < list.size(); j++) {
                    if (size -j == i - list.get(j) ||
                        size -j == list.get(j) - i) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {
                    continue;
                }
            }
            list.add(i);
            backTracking(n);
            list.removeLast();
        }
    }

    private List<String> getResult(LinkedList<Integer> list) {
        int size = list.size();
        return list.stream().map(e -> {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            while (i < size) {
                if (i == e) {
                    sb.append("Q");
                }else
                sb.append(".");
                i++;
            }
            return sb.toString();
        }).collect(Collectors.toList());

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值