算法训练营Day25

#Java #回溯

开源学习资料

Feeling and experiences:

复原IP地址:力扣题目链接

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址 ,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

之前做过分割回文字符串,其中的关键点就在于对回文的判断,还有分割线的设定

该题目也很类似:

java 复制代码
class Solution {
    //还是设置两个全局变量
    List<String> ans = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
    //思路和分割回文串相似
     if(s.length() == 0){
         return new ArrayList<>();
     }
     back(s,0);
     return ans;
    }

    public void back(String s,int startIndex){
        //终止条件
        
        if(path.size() > 4){
            return;
        }
        if(path.size() == 4 && startIndex >= s.length()){
            String temp = String.join(".",path);
            ans.add(temp);
            return;
        }

        for(int i = startIndex;i<s.length();i++){
            if(isValid(s,startIndex,i)){
                String str = s.substring(startIndex,i+1);
                path.add(str);
            }
            else{
                continue;
            }
            back(s,i+1);
            path.remove(path.size()-1);
        }
 
    }
    //判断字符串在区间[start,end]是否合法
    public boolean isValid(String s , int start,int end){
        if(start > end){
            return false;
        }
        //不能有前导0
        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;
            }
            //不能大于255
            num = num * 10 + (s.charAt(i) - '0');
            if(num > 255){
                return false;
            }
        }
        return true;
    }
}

与分割回文串的差别:

终止条件:

• 如果path中的段数超过4,说明不是有效的IP地址,直接返回。

• 如果path中的段数等于4且遍历完了整个字符串s,则将path中的段用点号连接起来,加入到ans列表中。

• 从startIndex开始,遍历字符串s的每个字符。

• 调用isValid函数判断当前切割的子串是否有效。如果有效,将其加入path中。

• 递归调用back函数,探索下一个字符。

• 回溯:完成对当前段的探索后,从path中移除最后加入的段。

还有就是字符串的合法条件(不难,但是多~有些地方容易漏掉)

子集:力扣题目链接

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

都是在回溯这一章节,那这道题又和之前的题有什么区别呢?

我感觉代码随想录中有一句话总结的很好:

子集是收集树形结构中树的所有节点的结果。

而组合问题、分割问题是收集树形结构中叶子节点的结果。

java 复制代码
class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
    
    back(nums,0);
    return ans;
    }

    public void back(int[] nums,int startIndex){
       //终止条件
       ans.add(new ArrayList<>(path));
       if(startIndex >= nums.length){
           return;
       }
       for(int i = startIndex;i<nums.length;i++){
           path.add(nums[i]);
           back(nums,i+1);
           path.remove(path.size()-1);
       }
    }
}

这道题练习完,可以把它归为一道模板题

注意:终止条件中的if判断可以删除,(本来就是一个栈,最终会弹栈)

子集II:力扣题目链接

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

这道题在子集的基础又有运用了之前 组合II 问题的去重(可以说是,子集模板 + 去重模板)

java 复制代码
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;
        }
        Arrays.sort(nums);
        used = new boolean[nums.length];
        subsetsWithDupHelper(nums, 0);
        return result;
    }
    
    private void subsetsWithDupHelper(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;
            subsetsWithDupHelper(nums, i + 1);
            path.removeLast();
            used[i] = false;
        }
    }
}

同样的,可以不用used数组:

java 复制代码
class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if (nums.length == 0){
            result.add(path);
            return result;
        }
        Arrays.sort(nums);
        subsetsWithDupHelper(nums, 0);
        return result;
    }
    
    private void subsetsWithDupHelper(int[] nums, int startIndex){
        result.add(new ArrayList<>(path));
        if (startIndex >= nums.length){
            return;
        }
        for (int i = startIndex; i < nums.length; i++){
            if (i > startIndex && nums[i] == nums[i - 1]){
                continue;
            }
            path.add(nums[i]);
            subsetsWithDupHelper(nums, i + 1);
            path.removeLast();
        }
    }
}

江畔何人初见月?

江月何年初照人?

Fighting!

相关推荐
keren21 小时前
SceneDock:Windows 场景化工作台——一键启动工作链,还能被 AI Agent 调用(CLI / MCP)
windows·开发工具·效率工具·mcp
澳鹏Appen1 小时前
澳鹏重磅发布ExamOCRBench:面向端到端试卷判分的多任务基准
算法·benchmark·基准评测
benjormin1 小时前
Java数据结构 二叉搜索树
数据结构·算法
人工智能培训2 小时前
知识图谱:结构化表达实体与关系的知识组织技术
大数据·人工智能·算法·重构·生活·知识图谱
地平线开发者2 小时前
QAT 实战:从 PyTorch 模型到 J6E 实板精度与延时验证
pytorch·算法·自动驾驶
IT星宿2 小时前
github-gravity:用 Rapier2D 把 GitHub 贡献图做成 SVG 物理动画
算法·github
♡すぎ♡3 小时前
SWE 的基本条件
算法·swe·浅水模拟
成旭先生3 小时前
车辆、能源与地理数据 API 实战:把定价、油价、行政区划串成一条链路
人工智能·windows·能源·api集成·油价查询·车辆定价·地址清洗
郝学胜-神的一滴4 小时前
AI 编程智能体 17:四步搞定专属AI智能体
大数据·人工智能·python·神经网络·算法·langchain·强化学习
seahahacsdn4 小时前
Windows获取SYSTEM用户权限的方法应用-计划任务
windows