代码随想录-2023/07/24

119 阅读1分钟

回溯算法

93.复原IP地址

分割法:

  1. 注意, 需要用变量point记录分割的段数, 不然分割的段数超过了4段, 必然是不合法的
  2. 在分割了四段的时候, 判断最后一段的末尾是不是整个字符串的末尾(判断是否四段时候刚好用掉了全部的字符)
  3. 需要对切割的字符串进行合法性判断(去掉前导0和小于255)

代码:

class Solution {
    List<String> ans = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        if(s.length() > 12) return ans;
        backtracking(s, "", 0, 0);
        return ans;
    }
    // 用point记录分割的段数, 若已经分割了四段, 则应该进行判断start是否到字符串末尾
    // 若到了末尾, 则代表分割合理, 应该收集结果, 否则不合理
    public void backtracking(String s, String path, int start, int point) {
        // 递归出口: 分割四段
        if(point == 4) {
            if(start == s.length()) {
                 ans.add(path.substring(0, path.length()-1));
            } 
            return;
        }
        for(int i=start; i<s.length(); i++){
            String str = s.substring(start, i+1);
            // 去掉前导0
            if((str.length() > 1 && str.charAt(0)-'0' == 0) || Integer.parseInt(str) > 255){
                return;
            }
            backtracking(s, path+str+".", i + 1, point + 1);
        }
    }
}

78.子集

注意:

  1. 组合和回溯问题一般都收集叶子节点的值
  2. 子集问题一般对树上面的每个节点的值都需要进行收集

代码:

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    LinkedList<Integer> list = new LinkedList<>();
    public List<List<Integer>> subsets(int[] nums) {
        ans.add(new ArrayList<>(list));
        backtracking(nums, 0);
        return ans;
    }
    public void backtracking(int[] nums, int start) {
        // start代表本层的起点, i代表本层目前走到的点
        for(int i = start; i < nums.length; i++){
            list.add(nums[i]);
            // 把路径上的所有节点值都收集到
            ans.add(new ArrayList<>(list));
            backtracking(nums, i + 1);
            list.removeLast();
        }
    }
}

90.子集II

  1. 解法同上
  2. 数组里面有重复元素,结果要求无重复---排序+横向去重

代码:

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    LinkedList<Integer> list = new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        ans.add(new ArrayList<>(list));
        backtracking(nums, 0);
        return ans;
    }

    public void backtracking(int[] nums, int start){
        for(int i=start; i<nums.length; i++){
            // 一般数组里面有重复元素, 但是结果里面不允许重复组合,需要横向去重
            if(i > start && nums[i]==nums[i-1]) continue;
            list.add(nums[i]);
            ans.add(new ArrayList<>(list));
            // 一般都需要纵向去重, 除非是排列, 前后顺序不同也算一种答案
            backtracking(nums, i+1);
            list.removeLast();
        }
    }
}