重生之我在代码随想录刷算法第二十一天 | 93.复原IP地址、78.子集、 90.子集II

参考文献链接:代码随想录

本人代码是Java版本的,如有别的版本需要请上代码随想录网站查看。

93.复原IP地址

力扣题目链接

解题思路

这道题目感觉跟昨天的分割回文串很像。

首先明确思路,先是一个一个字符去添加到StringBuilder,当该StringBuilder满足0到255要求时开启回溯去寻找第二个满足要求的。当题目给定字符串刚好被遍历完并且添加"."的次数是4次,那就说明我们刚好拼好了满足题意的ip地址。

我的代码时间复杂度和空间复杂度没有代码随想录的低,不过还可以,可以先通过我的思路理解这道题目再去代码随想录去优化代码。而且我的代码递归的参数也确实比较多。

代码示例

在代码注释中详细解释了递归的参数都是什么含义,并且解释了回溯隐藏在哪里

class Solution {
    List<String> result = new ArrayList<>();

    public List<String> restoreIpAddresses(String s) {
        if(s.length() > 12 || s.length() < 4){
            return result;
        }
        backtracking(s,0,new StringBuilder(),"",0);
        return result;
    }
    // s是题目给出的字符串,start是每次字符串遍历位置,stringBuilder用来拼接满足0-255的字符串
    //string用来把ip拼接起来,count用来计数拼接了几次了,超次数就return,剪枝操作
    public void backtracking(String s,int start,StringBuilder stringBuilder,String string,int count){
        if(count > 4){
            return;
        }
        if(start == s.length()){
            if(count == 4){
                result.add(string.substring(0,string.length() - 1));
            }else{
                return;
            }
        }
        for(int i = start;i < s.length();i++){
            stringBuilder.append(s.charAt(i));
            if(isVaild(stringBuilder.toString())){
                //回溯隐藏在这里,两个回溯,一个是string字符串的,一个是count的回溯
                backtracking(s,i + 1,new StringBuilder(),string + stringBuilder.toString() + ".",count + 1);
            }
        }

    }
    public boolean isVaild(String s){
        if (s.charAt(0) == '0' && s.length() != 1) { // 0开头的数字不合法
            return false;
        }
        Long temp = Long.parseLong(s);
        if(temp < 0 || temp > 255){
            return false;
        }
        return true;
    }
}

78.子集

力扣题目链接

解题思路

这道题目是找子集的,但模板跟前面的组合大差不差,我们直接上代码解释。

代码示例

为什么这次不用判断条件就可以往result添加了呢,因为这次是子集,任意一种情况都是可以添加的。

然后我们再通过start确保每种情况不会重复,比如1,2这种情况,那2开始后只有2,3.没有2,1.

class Solution {

    List<Integer> paths = new ArrayList<>();
    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums,0);
        return result;
    }
    public void backtracking(int[] nums,int start){
        result.add(new ArrayList<>(paths));
        if(start == nums.length){
            return;
        }
        for(int i = start;i < nums.length;i++){
            paths.add(nums[i]);
            backtracking(nums,i+1);
            paths.remove(paths.size() - 1);
        }
    }
}

90.子集II

力扣题目链接

解题思路

这道题目跟上一题唯一区别就是数组中有重复的元素,那我们其实之前几天作过这样的题目,只要用一个boolean数组去记录使用过哪个元素就好。

if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false){
                continue;
            }

当我们发现当前元素和前一个元素相同,那我们就判断前一个元素是否被使用了,如果被使用说明是树根之间的,可以使用。

如果没使用说明他俩是树层之间的需要去重。

代码示例
class Solution {

    List<Integer> paths = new ArrayList<>();
    List<List<Integer>> result = new ArrayList<>();
    boolean[] used;

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        used = new boolean[nums.length];
        Arrays.sort(nums);
        Arrays.fill(used,false);
        backtracking(nums,0);
        return result;
    }
    public void backtracking(int[] nums,int start){
        result.add(new ArrayList<>(paths));
        if(start == nums.length){
            return;
        }
        for(int i = start;i < nums.length;i++){
            if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false){
                continue;
            }
            paths.add(nums[i]);
            used[i] = true;
            backtracking(nums,i+1);
            paths.remove(paths.size() - 1);
            used[i] = false;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值