代码随想录day28, 复原IP地址, 子集I/II

复原IP地址

原理类似于切割回文串, 也是需要切割

这里的终止条件有点不同, 因为明确规定只能为四段, 所以分割为四段就是终止条件(startIndex其实就是风格先)

  1. 终止条件, pointSum == 3, 然后对最后一段进行判断isValid(s, startInex, s.size() - 2)左闭右闭
  2. 单层递归要判断isValid(s, startIndex, i), 这里的区间要注意, start是左区间固定的
  3. 回溯操作, 插入, 然后pointSum先加,后减, 可以发现其实并不是一个真的逗点

判断isValid的条件:

start > end, return false, 0开头的数字不行(用charAt), 遇到非数字字符不行, 大于255不行

下面直接拉代码, 用一个StringBuilder还是比较方便的

class Solution {
    List<String> res = new ArrayList<>();
    StringBuilder sb = new StringBuilder();
    public List<String> restoreIpAddresses(String s) {
        sb.append(s);
        backtracking(sb, 0, 0);
        return res;
    }

    public void backtracking(StringBuilder sb, int start, int pointNum){
        if(pointNum == 3){
            if(isValid(sb, start, sb.length() - 1)){
                res.add(sb.toString());
                return;
            }
        }
        for(int i = start; i < sb.length(); i++){
            //注意这里的左右区间。 start不变, i是会变的
            if(isValid(sb, start, i)){
                //这个方法实在i + 1的位置加上'.'
                sb.insert(i + 1, '.');
                pointNum++;
				//这里回溯要写i + 2, 因为他加上一个字符一个点是2,end注意是pointNum
                backtracking(sb, i + 2, pointNum);
                pointNum--;
				//这里回溯撤回i + 1, 也就是.的位置
                sb.deleteCharAt(i + 1);
                
            } else {
                break;
            }
        }

    }


    public boolean isValid(StringBuilder sb, int start, int end){
        if(start > end){
            return false;
        }
        //判断开头字母不能为0
        if(sb.charAt(start) == '0' && start != end){
            return false;
        }
        //判断非数字字符也not valid
        int num = 0;
        //这里的便利要注意, 左右边界都会改变的
        for(int i = start; i <= end; i++){
            if(sb.charAt(i) < '0' || sb.charAt(i) > '9'){
                return false;
            }
            num = num*10 + (sb.charAt(i) - '0');
            if(num > 255){
                return false;
            }
        }
        return true;
    }
}

子集

(给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集)

组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

剩余集合为空的时候,就是叶子节点, 也就是startIndex≥nums.length时, 说明全部元素都取完了

细节:

  1. 这里的收集子集不需要进入if判断, 而是每一个节点都需要收集
  2. 这里的判断终止条件就是start大于等于长度了, 说明都找完了
class Solution {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums, 0);
        return res;
    }

    public void backtracking(int[]nums, int start){
        //遍历的时候要把每个节点都记下来, 而不是到终止条件才记
        res.add(new ArrayList<>(path));
        //唯一的区别就是这里的终止条件,找完所有元素就结束
        if(start >= nums.length){
            return;
        }
        for(int i = start; i < nums.length; i++){
            path.add(nums[i]);
            backtracking(nums, i + 1);
            path.remove(path.size() - 1);
        }
    }     
}

子集II

和上一题的区别就是, 数组里和会有重复, 而解集不能重复

而这里的去重逻辑和之前的组合总和II一模一样, 就是判断树层

class Solution { 
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {\
        //别忘记也要sort
        Arrays.sort(nums);
        backtracking(nums, 0);
        return res;
    }

    private void backtracking(int[] nums, int start){
        res.add(new ArrayList<>(path));
        if(start >= nums.length){
            return;
        }

        for(int i = start; i < nums.length; i++){
            //和之前的组合总和II同理,去重
            if(i > start && nums[i] == nums[i - 1]){
                continue;
            }
            path.add(nums[i]);
            backtracking(nums, i + 1);
            path.remove(path.size() - 1);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值