力扣刷题Day23

93.复原IP地址

题目链接:力扣

这道题也是对字符串进行切割,和131题非常相似,但是需要判断是否符合要求(在0-255之间,且不能含有前导0)。

树形结构:

 回溯三部曲:

1.输出以及输入的参数:输出-void;输入-【两个全局变量:List<String> result,String ns - 储存目前分割的字符串】;backtracking(String s,int index, int pointSum - 当前字符串被分割的段);

2.终止条件:if(index == s.length && pointSum == 4) 将当前字符串储存,返回;if(index == s.length || pointSum == 4  )返回;

3. 单层循环逻辑:for(int i= index; i<s.length() & i<index+3; i++) 截取[index, i]这段数字,判断是否符合,如果不符合则break,结束循环。若是合法,则将这段数字加入ns中,pointSum++, 递归 - backtracking(s, i+1);回溯 - pointSum--,  删除ns中的数字。

具体代码实现:

class Solution {
    public List<String> restoreIpAddresses(String s) {
        result = new ArrayList<>();
        ns = new StringBuffer();

        if(s.length()<4 || s.length()>12) return result;
        
        backtraking(s, 0, 0);

        return result;

    }

    List<String> result;
    StringBuffer ns;

    public void backtraking(String s, int index, int points){
        //终止条件 - 这里的points指的是被分割的段数
        if(points == 4 && index == s.length()){
            result.add(ns.toString());
            return;
        }
        if(index == s.length() || points == 4){
            return;
        }
        
        //剪枝
        for(int i=index; i<s.length()&& i<index+3; i++){
            String m = s.substring(index, i+1);
            if(isValid(m)){
                
                ns.append(s.substring(index, i+1));
                
                //如果超过3个则不需要增加点
                if(points <3){
                    ns.append(".");
                }
               
               points++;

               backtraking(s, i+1, points);
                
                //回溯
               points--;
                //删除的时候要把增加的点都算上去
               ns.delete(index+points, i+points+2);
            }
        }
    }

    public boolean isValid(String m){
        if(m.length() == 0){
            return false;
        }
        
        //判断是否存在先导零
        if(m.charAt(0) == '0' && m.length() != 1){
            return false;
        }
        
        //判断是否都是数字
        for(int i=0; i<m.length(); i++){
            if(!Character.isDigit(m.charAt(i))){
                return false;
            }
        }
        
        判断数字的大小是否符合
        int n = Integer.parseInt(m);
        if(n>255 || n<0){
            return false;
        }

        return true;
    }
}

参考资料:代码随想录 

78.子集

题目链接:力扣

这道题和之前的组合、分割问题的区别是:

如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

回溯三部曲:

1.输出和输入参数:输出 - void;输入- 【两个全局变量 - List<List<Integer>> result; List<Integer> list】, backtraking(int[] nums, int startIndex);

2.终止条件:if(startIndex == nums.length()) 返回;

3.单层循环逻辑:for(int i = startIndex; i<nums.length; i++) 将nums[i]放入list;将list放入result;backtracking(nums, i+1);回溯 - 将nums[i]从list删除;

具体代码实现:

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        result = new ArrayList<>();
        list = new ArrayList<>();
        //放入空子集
        result.add(new ArrayList<>(list));

        backtraking(nums, 0);

        return result;

    }

    List<List<Integer>> result;
    List<Integer> list;

    public void backtraking(int[] nums, int startIndex){
        if(startIndex == nums.length){
            return;
        }

        for(int i=startIndex; i<nums.length; i++){
            list.add(nums[i]);
            //将每一个叶子结点放入结果集
            result.add(new ArrayList<>(list));

            backtraking(nums, i+1);
            
            //回溯
            list.remove(list.size()-1);
        }
    }
}

参考资料:代码随想录 

90.子集II 

这道题和78.子集很像,但是数组中含有重复元素,因此需要进行去重 - 注意:这里去重不能只是在循环的时候判断nums内部的值,还需要使用一个used数组进行标记。

同样是需要储存所有叶子结点的结果集。

回溯三部曲:

1.输出和输入参数:输出 - void;输入- 【两个全局变量 - List<List<Integer>> result; List<Integer> list】, backtraking(int[] nums, int startIndex, int[] used);

2.终止条件:if(startIndex == nums.length()) 返回;

3.单层循环逻辑:for(int i = startIndex; i<nums.length; i++) 【去重 - 如果 i>0 && nums[i] == nums[i-1] && used[i-1] == false, continue】; 将nums[i]放入list;将list放入result;将used[i] 标记为 ture;backtracking(nums, i+1);回溯 - 将nums[i]从list删除;将used[i] 标记为false;

具体代码实现:

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        result = new ArrayList<>();
        list = new ArrayList<>();
        result.add(new ArrayList<>(list));

        //排序
        Arrays.sort(nums);

        used = new boolean[nums.length];

        backtraking(nums, 0, used);

        return result;
    }

    List<List<Integer>> result;
    List<Integer> list;
    boolean[] used;

    public void backtraking(int[] nums, int startIndex, boolean[] used){
        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;
            }

            used[i] = true;
            list.add(nums[i]);
            //将叶子结点放入结果集
            result.add(new ArrayList<>(list));
            

            backtraking(nums, i+1, used);
            
            //回溯
            used[i] = false;
            list.remove(list.size()-1);
            
        }
    }
}

参考资料:代码随想录 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值