代码随想录算法训练营第31天 回溯算法 93.复原IP地址 78.子集 90.子集II

LeetCode 93.复原IP地址

题目讲解

思路

  • 递归参数

startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。

本题我们还需要一个变量pointNum,记录添加逗点的数量。

  • 递归终止条件

终止条件和131.分割回文串 (opens new
window)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。

pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。

然后验证一下第四段是否合法,如果合法就加入到结果集里

  • 单层搜索的逻辑

在131.分割回文串 (opens new window)中已经讲过在循环遍历中如何截取子串。

在for (int i = startIndex; i < s.size(); i++)循环中 [startIndex, i]
这个区间就是截取的子串,需要判断这个子串是否合法。

如果合法就在字符串后面加上符号.表示已经分割。

如果不合法就结束本层循环,如图中剪掉的分支:

在这里插入图片描述

然后就是递归和回溯的过程:

递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符.),同时记录分割符的数量pointNum 要
+1。

回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要-1。

class Solution {
    List<String> result = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
       if( s.length()>12)return result;
       backtrack(s,0,0);
       return  result;
    }
    public void backtrack(String s,int StartIndex,int pointNum)
    {
       if(pointNum ==3)
       {
           if( isvalid( s,StartIndex,s.length()-1))
           {
               result.add(s);
              
           }
           return;
       }
       for(int i=StartIndex;i<s.length();i++)
       {
           if(isvalid(s,StartIndex,i))
           {
               s= s.substring(0,i+1) +"."+s.substring(i+1);
               pointNum++;
               backtrack(s,i+2,pointNum);
               pointNum--;
               s= s.substring(0,i+1)+s.substring(i+2);
           }else
           {
               break;
           }
       }

    }

    public boolean isvalid(String s, int start ,
    int end)
    {
        if( start>end ) 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) >'9'|| s.charAt(i)<'0') 
             return false;
             num=num*10+(s.charAt(i)-'0');
             if(num>255)  return false;
        }
        return true;
        
    }
}

LeetCode 78.子集

题目讲解

思路

  • 递归函数参数

全局变量数组path为子集收集元素,二维数组result存放子集组合。(也可以放到递归函数参数里)

递归函数参数在上面讲到了,需要startIndex。

  • 递归终止条件

其实可以不需要加终止条件,因为startIndex >= nums.size(),本层for循环本来也结束了。

  • 单层搜索

求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
           subsetsHelper(nums,0);
           return result;
    }
    public void subsetsHelper(int[] nums, int startIndex)
    {
        result.add(new ArrayList<>(path));
        for(int i=startIndex;i<nums.length;i++)
        {
            path.add(nums[i]);
            subsetsHelper(nums,i+1);
            path.removeLast();
        }
    }
}

LeetCode 90.子集II

题目讲解

难点

结合了前面的子集 和组合总和 的知识点 要晓得树层去重
还会用到used数组,

如果要是全排列的话,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
          if( nums.length==0)
           { result.add(path);
            return result;
           }
           used= new boolean[nums.length];
           Arrays.sort(nums);
           backtrack(nums,0);
           return result; 
    }
    public void backtrack(int[]nums, 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])
            {
                continue;
            }
            path.add(nums[i]);
            used[i]= true;
            backtrack(nums,i+1);
            path.removeLast();
            used[i]= false;
        }
    }
}

总结

大多数优秀的程序员从事编程工作,不是因为期望获得报酬或得到公众的称赞,而是因为编程是件有趣的事儿

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值