Day24补代码随想录20250108 93.复原IP地址|78.子集|90.子集II

LeetCode三题:复原IP地址与子集问题

Day24补代码随想录20250108 93.复原IP地址|78.子集|90.子集II

93.复原IP地址

题目

有效 IP 地址 正好由四个整数(每个整数位于 0255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" "192.168.1.1"有效 IP 地址,但是 "0.011.255.245""192.168.1.312""192.168@1.1"无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的 有效 IP 地址 ,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

示例 1:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:

输入:s = "0000"
输出:["0.0.0.0"]

示例 3:

输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 1 <= s.length <= 20
  • s 仅由数字组成

思路

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 参数和返回值,startIndex(记录下一层递归分割的起始位置),pointNum记录添加逗点的数量。
  • 思路
    • 主函数public List <String> restoreIpAddresses(String s)
      • 剪枝,当长度>12,一定不符合条件
      • backTracking(s,0,0);
      • return result;
    • backTracking(String s,int startIndex,int pointNum)
      • 终止条件,逗号数量pointNum=3,最后还有一段没有判断
      • 判断第四段子字符串是否合法,如果合法就放进result中 [startIndex,s.length()-1]
      • for循环
        • 如果合法 if(isValid(s,startIndex,i))就递归回溯
          • 处理节点, s=s.substring(0,i+1)+“.”+s.substring(i+1); //[)中间插入,其中后项为[i+1,末尾]的s值
          • pointNum++;
          • 递归
          • 回溯
            • pointNum–;
            • s=s.substring(0,i+1)+s.substring(i+2);
      • isValid(String s,int start,int end)
        • start>end
        • 不是数字0的开头0不合法
        • for
          • 遇到非数字字符
          • 大于255不合法
  • 代码
    class Solution {
        List<String> result=new ArrayList<>();
        public List<String> restoreIpAddresses(String s) {
            if(s.length()>12) return result;//剪枝,一定不符合条件
            backTracking(s,0,0);
            return result;  
        }
        // startIndex: 搜索的起始位置, pointNum:添加逗点的数量
        public void backTracking(String s,int startIndex,int pointNum){
            //终止条件,逗点数量=,但是后面还剩一段没有判断
            if(pointNum==3){
                //判断第四段子字符串是否合法,如果合法就放进result中
                if(isValid(s,startIndex,s.length()-1)){
                    result.add(s);
                }
                return;
            }
            //for循环
            for(int i=startIndex;i<s.length();i++){
                if(isValid(s,startIndex,i)){
                    s=s.substring(0,i+1)+"."+s.substring(i+1);   //[)中间插入,其中后项为[i+1,末尾]的s值
                    pointNum++;
                    backTracking(s,i+2,pointNum);//插入逗点之后下一个字串的起始位置为i+2
                    pointNum--;//回溯
                    s=s.substring(0,i+1)+s.substring(i+2);//回溯删除,
                }else{
                    break;
                }
            }
    
        }
        // 判断字符串s在左闭⼜闭区间[start, end]所组成的数字是否合法
        private Boolean isValid(String s,int start,int end){
            //特殊的false情况1,始末颠倒
            if(start>end){
                return false;
            }
            //开头为0不合法,但是整数可以时单0
            if(s.charAt(start)=='0'&&start!=end){
                return false;
            }
            int num=0;
            for(int i=start;i<=end;i++){
                //遇到非数字字符
                if(s.charAt(i)>'9'||s.charAt(i)<'0'){
                    return false;
                }
                //大于255不合法
                num=num*10+(s.charAt(i)-'0');
                if(num>255){
                    return false;
                }
            }
            return true;
        }
    }
    

总结

  • startIndex是一定需要的,不能重复分割,记录下一层递归分割的起始位置。
  • 情况很复杂,判断情况多,需要考虑得很全面,这道题挺难的。

78.子集

题目

【收集树形结构中每一个节点的结果】

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

思路

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 思路
    • 收获结果的时候要取每一个节点的结果
  • class Solution {
        List<List<Integer>> result=new ArrayList<>();
        List<Integer> path=new LinkedList<>();
        public List<List<Integer>> subsets(int[] nums) {
            backTracking(nums,0);
            return result;
        }
        public void backTracking(int[] nums,int startIndex){
            result.add(new ArrayList<>(path));//提前加进去结果,以免遗漏最后一个值
            //终止条件
            if(startIndex>nums.length){
                return;
            }
            for(int i=startIndex;i<nums.length;i++){
                path.add(nums[i]);
                backTracking(nums,i+1);
                path.removeLast();
    
    
            }
        }
    }
    

总结

  • 注意result.add(new ArrayList<>(path));//提前加进去结果,以免遗漏最后一个值 这句代码要加在终止条件之前,以免遗漏

90.子集II

题目

【40.组合总和II和78.子集的结合】这道题用于测试我的学习效果

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

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

思路

  • 40.组合总和II和78.子集的结合

    class Solution {
        List<List<Integer>> result=new ArrayList<>();
        List<Integer> path=new LinkedList<>();
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            Arrays.sort(nums);
            backTracking(nums,0);
            return result;
        }
        public void backTracking(int[] nums,int startIndex){
            //提前保存结果
            result.add(new ArrayList<>(path));
            //终止条件 遍历到叶子节点
            if(startIndex>nums.length){
                return;
            }
            //for
            for(int i=startIndex;i<nums.length;i++){//横向
                //树层去重
                if(i>startIndex&&nums[i]==nums[i-1]){
                    continue;
                }
                path.add(nums[i]);
                backTracking(nums,i+1);//纵向递归
               path.removeLast();
            }
    }
    }
    

总结

  • 两个题的结合,没什么新知识点。
  • startIndex树层去重+保存每个节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值