代码随想录算法训练营Day24

复原IP地址

类似于上题的分割回文串
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

class Solution {  
    List<String> result = new ArrayList<>();  
  
    public List<String> restoreIpAddresses(String s) {  
        backtracking(s, 0, 0);  
        return result;  
    }  
    public void backtracking(String s,int start,int pointSum){//pointSum是逗号的个数  
        if(pointSum == 3){  
            if(isValid(s,start,s.length()-1)){  
                result.add(s);  
            }  
            return;  
        }  
        for(int i = start;i<s.length()-1;i++){  
            if(isValid(s,start,i)){  
                //插入.  
                s = s.substring(0, i + 1) + "." + s.substring(i + 1);  
                pointSum++;  
                backtracking(s,i+2,pointSum);//这里有.  
                //删除  
                pointSum--;  
                s = s.substring(0, i + 1) + s.substring(i + 2);  
            }else{  
                break;  
            }  
        }  
  
    }  
  
    private boolean isValid(String s, int start, int end) {  
        if (start > end) {  
            return false;  
        }  
        if (s.charAt(start) == '0' && start != end) { // 0开头的数字不合法  
            return false;  
        }  
        int num = 0;  
        for (int i = start; i <= end; i++) {  
            if (s.charAt(i) > '9' || s.charAt(i) < '0') { // 遇到⾮数字字符不合法  
                return false;  
            }  
            num = num * 10 + (s.charAt(i) - '0');  
            if (num > 255) { // 如果⼤于255了不合法  
                return false;  
            }  
        }  
        return true;  
    }  
}

子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

class Solution {  
    //之前的题在叶子节点收获结果,这道题在每个分支都取结果  
    List<List<Integer>> result = new ArrayList<>();  
    List<Integer> path = new ArrayList<>();  
    public List<List<Integer>> subsets(int[] nums) {  
        backTracking(nums,0);  
        return result;  
    }  
    public void backTracking(int[] nums,int startIndex){  
        result.add(new ArrayList<>(path));//每次进入一层递归,都将结果添加进path中  
        if(startIndex == nums.length){  
            //result.add(new ArrayList<>(path));这里和以前不一样  
            return;  
        }  
        for(int i = startIndex;i<nums.length;i++){  
            path.add(nums[i]);  
            backTracking(nums,i+1);  
            path.removeLast();  
        }  
    }  
}

子集2

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
与上面一题的区别在于,上面题不包含重复元素,而这道题包含重复元素,类似于之前的排序后再去重!
子集+组合总和2

class Solution {  
    //之前的题在叶子节点收获结果,这道题在每个分支都取结果  
    List<List<Integer>> result = new ArrayList<>();  
    List<Integer> path = new ArrayList<>();  
    boolean[] used;  
    public List<List<Integer>> subsetsWithDup(int[] nums) {  
        Arrays.sort(nums);  
        used = new boolean[nums.length];  
        backTracking(nums,0,used);  
        return result;  
    }  
    public void backTracking(int[] nums,int startIndex,boolean[] used){  
        result.add(new ArrayList<>(path));//每次进入一层递归,都将结果添加进path中  
        if(startIndex == nums.length){  
            //result.add(new ArrayList<>(path));这里和以前不一样  
            return;  
        }  
        for(int i = startIndex;i<nums.length;i++){  
            if (i>0  && nums[i - 1] == nums[i] && used[i-1]==false) continue;//后面条件保证了是树层上去重,**used[i]!=false**?  
            path.add(nums[i]);  
            used[i] = true;  
            backTracking(nums,i+1,used);  
            path.removeLast();  
            used[i] = false;  
        }  
    }  
}
  1. 树层去重原理
    nums[i] == nums[i-1]时:
  • used[i-1]==false表示前一个相同元素未被使用(说明是树层去重)
  • used[i-1]==true表示前一个元素在当前路径中被使用(是树枝上的重复)
  1. 第二段代码的问题
    used[i]!=false条件在当前元素未被处理时永远为false
  • 当进入循环时,used[i]初始值为false
    • 该条件会导致剪枝条件永远不成立
    • 最终导致无法正确去重
posted @ 2025-04-18 15:13  Anson_502  阅读(9)  评论(0)    收藏  举报