LeetCode Day28 93&78&90

128 阅读2分钟
93. 复原 IP 地址

同样是抽象成树形问题然后做切割处理,这样的话就可以联想到这题类似131可以用回溯来解决。

  1. 确定递归出入参:因为切割过的字符不能反复切割,所以需要startIndex确定当前切割线走到的位置,同时需要一个pointNum来记录添加逗点的数量。
  2. 递归终止条件:这里不能用切割线走到字符串终点来当作终止条件,因为前提已经说了IP地址是有四段的,所以当pointNum这个逗点有三个(说明这时字符串已经被切成四段了),并且切开的段都符合IP地址的要求时(0<x<255)这个结果是符合IP地址的,可以添加到结果集里面。
  3. 单层搜索逻辑:在for (int i = startIndex; i < s.size(); i++)循环中 [startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。如果合法就在字符串后面加上符号.表示已经分割。如果不合法就结束本层循环。以及需要注意递归和回溯的过程,因为需要在字符串中加入了分隔符.,回溯的时候需要把这个逗点删掉,同时pointNum-1;此外回溯期间因为添加了逗点的原因,遍历到下一个字符的位置应该就是i+2了。
class Solution {
    //存放最后的结果集
    List<String> res = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        //存放每次划分出来的str
        LinkedList<String> path = new LinkedList<>();
        backTrack(s, path, 0);
        return res;
    }

    //回溯算法
    private void backTrack(String s, LinkedList<String> path, int startIndex){
        //划分出来的str子串个数如果>4,说明不是IP地址,剪枝
        //比如s = "25525511135",假设最后path中存的是25.52.55.111.35,那么此时这个path的大小已经>4了,不符合IP地址的格式
        if(path.size() > 4) return;

        //startIndex是划分字串s的分割线,如果把划分的字串写成树状图,这个startIndex也就是当前遍历到这个树的层数;因此,当startIndex把整一个字串分割完了(这时startIndex也就走到了字串的末尾),并且path的长度大小刚好符合一个IP地址的规格时,我们把这一个path作为一个结果集存放到res中
        if(startIndex == s.length() && path.size() == 4){
            res.add(toRes(path));
            return;
        }

        //开始遍历(主要回溯过程)
        for(int i = startIndex; i < s.length(); i ++){
            //这一步是把当前遍历到的所在的子串从父字串s中裁剪下来
            String str = s.substring(startIndex, i + 1);
            //对这一个子串做判断(是否符合IP地址中digit的要求);如果符合,那么condition是false,这个continue就不执行,接着从30行往后开始走;如果不符合,condition为true,执行continue意味着30-32行都不执行,直接执行下一个for循环(也就是回到27行,继续裁出来一个新的子串来判断是否合规)
            if(!isVaild(str)) continue;
            //把合规的子串添加进path中,集满4个并且startIndex恰好走到结尾的话,就是19-22行代码了!(也就是我们想要的正确地址)
            path.add(str);
            //回溯
            backTrack(s, path, i + 1);
            path.removeLast();
        }
    }

    //把存在path中的合法IP地址子串遍历,在后面加.
    private String toRes(LinkedList<String> path){
        //声明一个StringBuilder用他来存储
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < path.size(); i ++){
            sb.append(path.get(i));
            if(i != path.size() - 1){
                sb.append(".");
            }
        }
        return sb.toString();
    }

    //判断当前截取的字符子串是否合规
    public boolean isVaild(String s){
        //如果截取的子串长度是1,合规(IP地址中的数字可以是一位)
        if(s.length() == 1) return true;

        //如果截取的子串长度大于3,不合规,因为有效的IP最大也就到255
        if(s.length() > 3) return false;

        //如果截取的子串首字符是0,不合规
        if(s.charAt(0) == '0') return false;

        //如果截取的子串数值>255也是不合规
        if(Integer.valueOf(s) > 255) return false;
        return true;
    }
}
78. 子集

对比起上一题这题仿佛一个简单题。

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

    public void backtrace(int[] nums, int idx){
        res.add(new ArrayList(path));
        if(idx >= nums.length) return;

        for(int i = idx; i < nums.length; i ++){
            path.add(nums[i]);
            backtrace(nums, i + 1);
            path.removeLast();
        }
    }
}
90. 子集 II

第一次提交因为判断条件没写清楚,修改一下直接过了

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

    public void backtrace(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] && !isused[i - 1]){
                continue;
            } 

            path.add(nums[i]);
            isused[i] = true;
            backtrace(nums, i + 1);
            isused[i] = false;
            path.removeLast();
        }
    }
}