day28|● 93.复原IP地址 ● 78.子集 ● 90.子集II

93. 复原IP地址

题目链接:https://leetcode.com/problems/restore-ip-addresses

A valid IP address consists of exactly four integers separated by single dots. Each integer is between 0 and 255 (inclusive) and cannot have leading zeros.
For example, “0.1.2.201” and “192.168.1.1” are valid IP addresses, but “0.011.255.245”, “192.168.1.312” and “192.168@1.1” are invalid IP addresses.
Input: s = “25525511135”
Output: [“255.255.11.135”,“255.255.111.35”]

在这里插入图片描述

思路:

  1. 切割问题(类似组合问题)
  2. 注意isvalid函数三种情况,>255的判定

java.lang.NumberFormatException: For input string: "9245587303" at line 67, java.base/java.lang.NumberFormatException.forInputString

方法一:用path存4段,再接起来

class Solution {
    List<String> result = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        backtracking(s, 0);
        return result;
    }
    private void backtracking(String s, int startIndex){
        if (path.size() == 3){
            if (isValid(s, startIndex, s.length()-1)){
                StringBuilder ip = new StringBuilder();
                for (String subStr: path) {
                    ip.append(subStr);
                    ip.append(".");
                }
                ip.append(s.substring(startIndex, s.length()));
                result.add(ip.toString());
            }
            return;
        }
        for (int i = startIndex; i < s.length(); i++) {
            if (isValid(s, startIndex, i)) {
                path.add(s.substring(startIndex, i+1));
                backtracking(s, i+1);
                path.remove(path.size()-1);
            } else{
                break;
            }
        }
    }

    private Boolean isValid(String s, int start, int end){
        if (start > end) return false; // 注意
        String subStr = s.substring(start, end+1);
        int num = 0;
        for (int i = 0; i < subStr.length(); i++) {
            if (!Character.isDigit(subStr.charAt(i))) {
                return false;
            }
            num = num * 10 + (subStr.charAt(i) - '0'); // 注意
            if (num > 255) { // 如果⼤于255了不合法
                return false;
            }
        }
        if (subStr.length() > 1 && subStr.charAt(0) == '0') {
            return false;
        }
        return true;
    }
}

方法二:直接append".",backtracking需要i+2来跳过“.”

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 sb, int startIndex, int pointSum) {
        if (pointSum == 3) {
            if (isValid(sb, startIndex, sb.length()-1)) {
                result.add(sb.toString());
            }
            return;
        }
        for (int i = startIndex; i < sb.length(); i++){
            if (isValid(sb, startIndex, i)) {
                sb.insert(i+1, '.');
                backtracking(sb, i+2, pointSum+1);
                sb.deleteCharAt(i+1);
            } else {
                break;
            }
        }
    }
    private Boolean isValid(StringBuilder sb, int start, int end) {
        if (start > end) {
            return false;
        }
        if (end != start && sb.charAt(start) == '0') {
            return false;
        }
        int num = 0;
        for (int i = start; i <= end; i++) {
            if (sb.charAt(i) > '9' || sb.charAt(i) < '0') {
                return false;
            }
            num = num * 10 + (sb.charAt(i) - '0'); // zhuyi
            if (num > 255) {
                return false;
            }
        }
        return true;
    }
}

时间复杂度: O(3^4),IP地址最多包含4个数字,每个数字最多有3种可能的分割方式,则搜索树的最大深度为4,每个节点最多有3个子节点。
空间复杂度: O(n)

78.子集

题目链接:https://leetcode.com/problems/subsets

Given an integer array nums of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

在这里插入图片描述

思路:

  1. 子集是无序的,取过的元素不会重复取,写回溯算法的时候,从startindex开始,而不是从0开始!
  2. 组合和分割找叶子节点,子集找所有节点。
  3. 不需要剪枝,需要遍历整棵树。
class Solution {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums, 0);
        return result;
    }
    private void backtracking(int[] nums, int startIndex) {
        result.add(new ArrayList<>(path)); // 放在终止之后就会遗漏放入最后一个结果[1,2,3]
        if (startIndex == nums.length) { //也可以不写
            return;
        }
        for (int i = startIndex; i < nums.length; i++) {
            path.add(nums[i]);
            backtracking(nums, i+1);
            path.remove(path.size()-1);
        }
    }
}

90.子集II

题目链接:https://leetcode.com/problems/subsets-ii/

Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
示例:
输入: [1,2,2]
输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]

在这里插入图片描述

思路:

  1. 集合里有重复元素了,而且求取的子集要去重
  2. 去重首先排序
  3. used数组标记
class Solution {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.sort(nums);
        backtracking(nums, used, 0);
        return result;
    }
    private void backtracking(int[] nums, boolean[] used, int startIndex){
        result.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] == false) { // 去重
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            backtracking(nums, used, i+1);
            path.remove(path.size()-1);
            used[i] = false;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值