代码随想录算法训练营第二十八天 | 93.复原IP地址、78.子集、90.子集II

93.复原IP地址

题目链接:https://leetcode.cn/problems/restore-ip-addresses/
文档讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html
视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/

思路

  • 我的思路:startIndex控制起始位置,i控制结束位置。截取出来的字符串用isIP()方法判断是否在0-255之间。用count来控制一共只有四段字符,并且最后一段字符后面不加.
  • 代码随想录:把加点的数量作为递归的参数,当点数为3,判断最后一段的合法性,如果合法就把s放入res,并且加点是直接在s上判断是否合法后加。

代码

我的方法

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

    public void backtracking(String s, int startIndex, int count) { 
        if (startIndex >= s.length() && count == 4) {
            res.add(path.toString());
            return;
        }

        for (int i = startIndex; i < s.length(); i++) {
            String temp = s.substring(startIndex, i + 1);
            if (isIP(temp)) {
                int start = path.length();
                path.append(temp);
                count++;
                if (count < 4) path.append(".");
                backtracking(s, i + 1, count);
                count--;
                path.delete(start, path.length());
            }
        }

    }

    public boolean isIP(String s) {
        int res = 0;
        if (s.length() > 3) return false;
        else if (s.length() == 3) { // 255
            if (s.charAt(0) == '0') return false; 
            for (int i = 0; i < s.length(); i++){
                if (s.charAt(i) - '0' > 9) return false;
            }
            res = (s.charAt(0) - '0') * 100 + (s.charAt(1) - '0') * 10 + (s.charAt(2) - '0');
            if (res > 255 || res < 0) return false;
        } else if (s.length() == 2) { // 23
            if (s.charAt(0) == '0') return false;
            for (int i = 0; i < s.length(); i++){
                if (s.charAt(i) - '0' > 9) return false;
            }
            res = (s.charAt(0) - '0') * 10 + (s.charAt(1) - '0');
            if (res > 255 || res < 0) return false;
        } else if (s.length() == 1) { // 3
            if (s.charAt(0) - '0' > 9 || s.charAt(0) - '0' < 0) return false;
        }
        return true;
    }
}

卡哥方法

class Solution {
    List<String> result = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        StringBuilder sb = new StringBuilder(s);
        backTracking(sb, 0, 0);
        return result;
    }
    private void backTracking(StringBuilder s, int startIndex, int dotCount){
        if(dotCount == 3){
            if(isValid(s, startIndex, s.length() - 1)){
                result.add(s.toString());
            }
            return;
        }
        for(int i = startIndex; i < s.length(); i++){
            if(isValid(s, startIndex, i)){
                s.insert(i + 1, '.');
                backTracking(s, i + 2, dotCount + 1);
                s.deleteCharAt(i + 1);
            }else{
                break;
            }
        }
    }
    //左闭右闭
    private boolean isValid(StringBuilder s, int start, int end){
        if(start > end)
            return false;
        if(s.charAt(start) == '0' && start != end)
            return false;
        int num = 0;
        for(int i = start; i <= end; i++){
            int digit = s.charAt(i) - '0';
            num = num * 10 + digit;
            if(num > 255)
                return false;
        }
        return true;
    }
}

78.子集

题目链接:https://leetcode.cn/problems/subsets/
文档讲解:https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html
视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci

思路

因为要所有子集的集合,所以每一层的每一个结点都要记录下来。

代码

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums, 0);
        return res;
    }

    public void backtracking(int[] nums, int startIndex) {
        res.add(new ArrayList<>(path)); // 把所有path都记录下来放入res
        if (startIndex >= nums.length) return;
        for (int i = startIndex; i < nums.length; i++) {
            path.add(nums[i]);
            backtracking(nums, i + 1);
            path.removeLast();
        }
    }
}

90.子集II

题目链接:https://leetcode.cn/problems/subsets-ii/
文档讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html
视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J

思路

  • 本题和之前的组合问题一样,数组中有重复元素,但结果中不能出现重复结果。所以需要对同层相同的数进行去重。首先对数组排序,然后在循环中去重。
  • 去重方法一:使用标记数组used。当遇到同层重复数时,判断前一个数的标记数组是否为false,如果是,就跳过当前数;如果不是,说明这个数是上一层使用过,不用跳过。
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue;
  • 去重方法二:不使用标记数组,使用startIndex 。注意这里的判断条件就改为了i > startIndex
if (i > startIndex && nums[i] == nums[i - 1]) continue;

代码

使用标记数组

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        used = new boolean[nums.length];
        Arrays.fill(used, false);
        backtracking(nums, 0);
        return res;
    }

    public void backtracking(int[] nums, int startIndex) {
        res.add(new ArrayList<>(path));
        if (startIndex >= nums.length) return;
        for (int i = startIndex; i < nums.length; i++) {
            if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue;
            used[i] = true;
            path.add(nums[i]);
            backtracking(nums, i + 1);
            used[i] = false;
            path.removeLast();
        }
    }
}

不使用标记数组

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

    public void backtracking(int[] nums, int startIndex) {
        res.add(new ArrayList<>(path));
        if (startIndex >= nums.length) return;
        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();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值