LeetCode:93.复原IP地址 && 78.子集 && 78.子集II

文章介绍了两种使用回溯算法解决的问题:一是从给定的数字字符串中恢复所有可能的有效IP地址,二是找到整数数组的所有子集(幂集)。这两种问题都利用了递归和回溯策略,避免生成重复结果,并对特定条件(如IP地址的段数和数值范围,以及子集的唯一性)进行了处理。
摘要由CSDN通过智能技术生成

93.复原IP地址

题目

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 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 中的任何数字。你可以按 任何 顺序返回答案。
在这里插入图片描述

回溯

class Solution {
    // 存放结果集
    List<String> res = new ArrayList<>();
    // 拼接字符串
    StringBuilder strb = new StringBuilder();
    public List<String> restoreIpAddresses(String s) {
        restoreIpAddresses(s, 0, 0);
        return res;
    }
    // start:确保s的数字全部读取完
    // number:确保ip分割为4段
    public void restoreIpAddresses(String s, int start, int number){
        // 当start == s的长度时,表示已经全部读取完毕
        // number == 4,表示ip被分为了4段,符合ip的规格要求
        if(s.length() == start && number == 4){
            res.add(strb.toString());
            return;
        }
        // s.length() == start || number == 4,只达到其中一个要求,并不算符合条件,直接返回
        if(s.length() == start || number == 4){
            return;
        }
        // 确保ip字段每个的长度不超过3位,并且保证字段在[0, 255]之间
        for(int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0 && Integer.parseInt(s.substring(start, i + 1)) <= 255; i++){
            // ip的长度大于1并且第一个数为“0”的话,则continue
            if(i + 1 - start > 1 && s.charAt(start) - '0' == 0){
                continue;
            }
            // 拼接字段
            strb.append(s.substring(start, i + 1));
            // 当ip的网段小于3时,才需要加“.”,如果等于3,则表示已经有3个网段了,则第4个网段后尾不需要加“.”
            if(number < 3){
                strb.append(".");
            }
            number++;
            restoreIpAddresses(s, i + 1, number);
            number--;
            // 删除strb最后一个网段
            strb.delete(start + number, i + number + 2);
        }
    }
}

78.子集

题目

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

回溯

class Solution {
    // 存放结果集
    List<List<Integer>> res = new ArrayList<>();
    // 收集符合条件的结果
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> subsets(int[] nums) {
        subsets(nums, 0);
        return res;
    }
    // startIndex:用来将元素进行子集的拼接操作
    public void subsets(int[] nums, int startIndex){
        // 为符合条件的结果,创建节点
        // 放在终止条件的上面是为了将[1,2,3]存入
        res.add(new ArrayList<>(path));
        // 终止条件
        if(startIndex >= nums.length) return;
        for(int i = startIndex; i < nums.length; i++){
            path.add(nums[i]);
            subsets(nums, i + 1);
            path.removeLast(); // 回溯
        }
    }
}

78.子集II

题目

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

回溯(有used)

class Solution {
    // 存放结果集
    List<List<Integer>> res = new ArrayList<>();
    // 收集符合条件的结果
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        // 如果nums为空时,将path(此时path为空)加入
        if(nums.length == 0){
            res.add(path);
            return res;
        }
        // 排序,为后面去重做准备
        Arrays.sort(nums);
        used = new boolean[nums.length];
        subsetsWithDup(nums, 0);
        return res;
    }
    // startIndex:用来将元素进行子集的拼接操作
    public void subsetsWithDup(int[] nums, int startIndex){
        // 为符合条件的结果,创建节点
        // 放在终止条件的上面是为了将[1,2,2]存入
        res.add(new ArrayList<>(path));
        // 终止条件
        if(startIndex >= nums.length) return;
        for(int i = startIndex; i < nums.length; i++){
            // 确保在下标位置不为0,前一个与后一个相同并且不为空的情况,则continue
            if(i > startIndex && nums[i] == nums[i - 1] && !used[i - 1]) continue;
            path.add(nums[i]);
            used[i] = true;
            subsetsWithDup(nums, i + 1);
            path.removeLast(); // 回溯
            used[i] = false; // 回溯
        }
    }
}

回溯(没有used)

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        subsetsWithDup(nums, 0);
        return res;
    }
    public void subsetsWithDup(int[] nums, int startIndex){
        res.add(new ArrayList<>(path));
        for(int i = startIndex; i < nums.length; i++){
            if(i > startIndex && nums[i] == nums[i - 1]) continue;
            path.add(nums[i]);
            subsetsWithDup(nums, i + 1);
            path.removeLast();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值