代码随想录第二十八天

Leetcode 93. 复原 IP 地址

题目链接: 复原 IP 地址
自己的思路:没有想到终止条件,也就是树有三层,拿逗点来当做终止条件!!!

正确思路:这道题和分割回文串很像,因为在进行下一次递归的时候都会判断一段区间是否合法,如果不合法直接下一个分割方案,而且这个题的终止条件为逗点数为3,但是逗点数为3的时候,说明前三个字符已经判断合法了,但是我们在加入之前还是要判断最后一个字符是否合法,如果合法我们才会把它加入到结果集中,难点在于思考什么当做终止条件和在下次递归的时候,startindex要加2,因为递归之前给他加了一个逗点,所以需要加2;回溯三部曲:1、传入参数:字符串、分割起始点以及逗点数;2、终止条件:当逗点数为3且最后一个字符也合法的时候,将s加入结果集中;3、单层逻辑:先判断以当前startindex为起始点分割的一点区间是否合法,如果不合法,考虑下一次分割方案,否则我们给当前节点下一个结点加一个.,然后逗点数+1,然后进入下层递归,再回溯即可!!!

代码:

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        if (s.length()>12) return res;
        backtracking(s,0,0);
        return res;
    }

    public void backtracking(String s,int startindex,int pointsum){
        //如果有三个逗点,则判断最后一个字符是否合法
        if (pointsum==3){
            if (isValid(s,startindex,s.length()-1))
            res.add(new String(s));
            return;
        }

        for (int i = startindex;i<s.length();i++){
            //如果不合法,直接下一个循环
            if (!isValid(s,startindex,i)) continue;
            s = s.substring(0,i+1) + '.' +s.substring(i+1);
            pointsum++;
            backtracking(s,i+2,pointsum);
            pointsum--;
            s = s.substring(0,i+1) +s.substring(i+2);
        }
    }
    //检验是否合法
    public boolean isValid(String s,int start,int end){
        if (end<start) return false;
        if (s.charAt(start)=='0'&&start!=end){
            return false;
        }
        int num = 0;
        for (int i =start;i<=end;i++){
            if (s.charAt(i)<'0'&&s.charAt(i)>'9') return false;
            num = num*10+s.charAt(i)-'0';
            if (num>255) return false;
        }
        return true;
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 78. 子集

题目链接: 子集
自己的思路:题目也不难,但就是想不到!!!!
正确思路:这个题和之前题的区别在于,它每次递归的时候,它都要加入到结果集中,所以它在是终止条件的上方加入path到结果集中;回溯三部曲:1、传入参数:数组和startindex指针;2、终止条件:先加入path到res结果集中,然后再终止,当startindex指向res的后面的时候,终止;3、单层逻辑:加入当前元素到path中,然后递归,然后回溯!!!

代码:

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

    public void backtarcking(int[] nums,int startindex){
        //一次递归就放一个结果
        res.add(new ArrayList(path));
        if (startindex==nums.length) return;

        for (int i =startindex;i<nums.length;i++){
            path.add(nums[i]);
            backtarcking(nums,i+1);
            path.removeLast();
        }
    }

}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 90. 子集 II

题目链接: 子集 II
自己的思路:这个题自己算是做出来了吧,used数组忘了咋那么写了。

正确思路:和之前存在相同元素的组合问题基本一个思路,只不过这个是收集子集问题;直接回溯三部曲:1、传入参数:数字、startindex指针还有used数组表示元素的使用情况;2、终止条件:先将该子集加入到结果集中,然后判断当前指针是否指向了nums数组的最后,如果是,则返回;3、单层递归:判断相同的两个数,前面的那个数是否已经使用过,如果使用过的话,则直接下一个方案,否则将当前元素加入到path中,然后当前元素的used设置为true,然后递归回溯!!!

代码:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        //必须先排序,不然相同的元素不一定是挨着的
        Arrays.sort(nums);
        used = new boolean[nums.length];
        backtarcking(nums,0,used);
        return res;
    }

    public void backtarcking(int[] nums,int startindex,boolean[] used){
    	//每个节点都收货子集
        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;
            path.add(nums[i]);
            used[i]=true;
            backtarcking(nums,i+1,used);
            path.removeLast();
            used[i]=false;
        }
    }
}

复杂度分析
时间复杂度: O ( n ) \mathcal{O}(n) O(n)
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值