[代码随想录Day24打卡] 93.复原IP地址 78.子集 90.子集II

news2025/7/15 3:28:26

93.复原IP地址

一个合法的IP地址是什么样的:
有3个’.'分割得到4个数,每个数第一个数不能是0,不能含有非法字符,不能大于255。
在这里插入图片描述
这个是否属于合法IP相当于一个分割问题,把一串字符串分割成4部分,分别判断每个部分是否合法,如果全部合法就保存结果,否则就return;
回溯三部曲

  1. 确定参数和返回值:参数要处理的字符串s,startIndex来防止我们重复分割和pointNum存储当前加的’.‘的个数。我们把path(存储当前的字符串)和result(存储加了’.'符合合法IP条件的字符串的结果列表)定义为了全局变量所以不需要返回值。
  2. 递归终止条件:if(pointNum==3)说明我们已经加了三个’.',然后直接判断最后一个数字是否合法,如果合法就保存结果,如果不合法就return。
  3. 单层递归逻辑:我们就是把整体字符串分段,分别判断每一段分割结果是否合法,如果合法就往字符串中加’.',并且递归调用backtracking进行下一次分割如果不合法就直接return不操作。
    当前分割的结果:startIndex指明当前循环中开始位置在这个循环过程中是不变的,i不断地向右循环,[startIndex, i]就是当前处理的字符串(就是IP地址中的一段,那段数字,我们只需要判断这段数字是否合法就可以)。
    分割标志:startIndex就是相当于分割标志,指明了前一次分割的位置。
    下面是C++、JAVA、Python的代码。
class Solution {
private:
    vector<string> result;
    bool isValid(const string& s, int start, int end){
        if(start>end){
            return false;
        }
        if(s[start]=='0' && start != end){//0开头的数字不合法
            return false;
        }
        int num = 0;
        for(int i = start; i <= end; i++){
            if(s[i]>'9' || s[i]<'0'){
                //遇到非法字符不合法
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if(num>255){
                //数字大于255不合法
                return false;
            }
        }
        return true;
    }
    void backtracking(string& s, int startIndex, int pointSum){
        if(pointSum == 3){
            //对最后一段的合法性进行判断
            if(isValid(s, startIndex, s.size()-1)){//
                result.push_back(s);
            }
            return;
        }//递归终止条件
        for(int i = startIndex; i < s.size(); i++){//单层递归
            if(isValid(s, startIndex, i)){
                s.insert(s.begin()+i+1, '.');
                pointSum += 1;
                backtracking(s, i+2, pointSum);
                s.erase(s.begin()+i+1);
                pointSum-=1;
            }
        }
    }
public:
    vector<string> restoreIpAddresses(string s) {
        if (s.size() < 4 || s.size() > 12) return result;
        backtracking(s, 0, 0);
        return result;
    }
};
class Solution {
    List<String> result = new ArrayList<>();//建立一个列表存储最终结果
    public List<String> restoreIpAddresses(String s) {
        backtracking(s, 0, 0);
        return result;
    }
    private void backtracking(String s, int startIndex, int pointNum){
        if(pointNum == 3){
            //如果逗号数量为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);//在str的后面插入"."
                pointNum++;
                backtracking(s, i+2, pointNum);//
                pointNum--;//回溯
                s = s.substring(0, i+1) + s.substring(i+2);//回溯删掉逗点,substring一个参数是从beginIndex开始到末尾,有两个参数从 beginIndex 开始到 endIndex 结束前(不包括 endIndex)提取子字符串
            }else{
                break;
            }
        }
    }
    //判断字符串s在左闭右闭区间[start, end]所组成的数字是否合法
    private Boolean isValid(String s, int start, int end){
        if(start > end){
            return false;
        }//start和end本身就不合法
        if(s.charAt(start) == '0' && start != end){
            //0开头的数字不合法
            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){
                //如果大于255了不合法
                return false;
            }
        }
        return true;
    }
}
class Solution(object):
    def __init__(self):
        self.result = []
    def restoreIpAddresses(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        if(len(s)<4 or len(s)>12):
            return self.result
        self.backtracking(s, 0, 0)
        return self.result
    def backtracking(self, s, startIndex, pointNum):
        #递归终止条件
        if(pointNum == 3):
            if(self.isValid(s, startIndex, len(s)-1)):
                self.result.append(s)#如果合法就存入
        for i in range(startIndex, len(s)):
            if(self.isValid(s, startIndex, i)):
                s = s[:i+1]+'.'+s[i+1:]
                pointNum+=1#往字符串中加入一个点
                self.backtracking(s, i+2, pointNum)
                s = s[:i+1] + s[i+2:]
                pointNum -= 1#回溯
    def isValid(self, s, start, end):#判断所给字符的合法性,左闭右闭区间
        #首先判断传入的参数是否合法
        if(start > end):
            return False
        #判断是否开头有0
        if s[start] == '0' and start!=end:
            return False
        num = 0#这个是存储当前这个子串对应的数值的
        for i in range(start, end+1):
            if s[i]>'9' or s[i]<'0':
                return False #判断每个字符是否合法
            num = num*10 + int(s[i])
            if(num > 255):
                return False#超出255非法
        return True
            
        

参考文章

  1. https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html

78.子集

在这里插入图片描述遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合。
注意:这个题目时每个节点的结果都要保存,不是只保存叶子节点。其他的和组合差不多。
回溯三部曲
1. 确定参数和返回值:参数就是数组nums和startIndex指示之前使用了那些元素,防止重复取数。我们把path金额result定义为全局变量,所以不需要返回值。
2. 遍历终止条件:startIndex>= nums.size() return;就是如果startIndex超出了数组的范围就停止递归。
单层递归的逻辑:i从startIndex到nums.size()遍历,每次遍历都把nums[i]当前元素加入到path当前结果中,然后backtracking()继续下层递归,然后path.pop_back()回溯。

class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int startIndex){
        result.push_back(path);
        if(startIndex>= nums.size()) return;//递归终止条件
        for(int i = startIndex; i < nums.size(); i++){
            path.push_back(nums[i]);
            backtracking(nums, i+1);
            path.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums, 0);
        return result;
    }
};
class Solution {
    List<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    public void backtracking(int[] nums, int startIndex){
        result.add(new ArrayList<>(path));
        if(startIndex>=nums.length){
            return;//递归终止条件
        }
        for(int i=startIndex; i < nums.length; i++){
            path.add(nums[i]);
            backtracking(nums, i+1);
            path.removeLast();
        }

    }
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums, 0);
        return result;
    }
}
class Solution(object):
    def __init__(self):
        self.result = []
        self.path = []
    def backtracking(self, nums, startIndex):
        self.result.append(list(self.path))#别忘了这个加list为了就是不指向同一个地址
        if(startIndex>=len(nums)):
            return
        for i in range(startIndex, len(nums)):
            self.path.append(nums[i])#存入元素
            self.backtracking(nums, i+1)
            self.path.pop()
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        self.backtracking(nums, 0)
        return self.result
        

参考文章

  1. https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html

90.子集II

在这里插入图片描述
这个就是子集和组合Ⅱ的应用。
秒了。
注意

  1. 对于有重复元素的题目,要去重,先排序。
  2. 设置used数组来判断时树枝还是树层。每个语言怎么定义要清楚。
  3. 保存结果的时候要根据每个语言,JAVA和Python都是需要处理一下path再加入到result中,不然result中的元素都指向同一个位置,最后结果都[]
  4. 去重的两行代码要记住。

回溯三部曲

  1. 确定参数和返回值:参数时数组nums和startIndex,返回值为None。
  2. 递归终止条件:看startIndex是否越界,如果越界就直接返回。没有也可以,因为后面for循环也会因为startIndex越界不运行直接return。
  3. 单层递归逻辑:加入去重的两行代码if(i>0 && nums[i]==nums[i-1] && used[i-1]==0)continue;(直接跳过,到不是重复的数,不是break,break会漏掉重复数字之后的所有的数字)然后把当前数字放到path中,更新used使当前索引的位置used[i]=true,然后backtracking()递归处理下一个数,path.pop(),used[i]=false回溯一下。
class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int startIndex, vector<bool> used){
        result.push_back(path);
        //想一下递归的终止条件
        // if(startIndex >= nums.size()) return;
        for(int i = startIndex; i < nums.size(); i++){
            if(i>startIndex && nums[i]==nums[i-1] && used[i-1]==0){
                continue;//跳过重复元素
            }
            path.push_back(nums[i]);
            used[i] = true;
            backtracking(nums, i+1, used);
            used[i] = false;
            path.pop_back();
        }
    }
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        sort(nums.begin(), nums.end());
        backtracking(nums, 0, used);
        return result;
    }
};
class Solution {
    List<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    public void backtracking(int[] nums, int startIndex, boolean[] used){
        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] == false){
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            backtracking(nums, i+1, used);
            used[i] = false;
            path.removeLast();
        }
    }
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);
        Arrays.sort(nums);
        backtracking(nums, 0, used);
        return result;
    }
}
class Solution(object):
    def __init__(self):
        self.result = []
        self.path = []
    def backtracking(self, nums, startIndex, used):
        self.result.append(list(self.path))
        if(startIndex>=len(nums)):#递归终止条件也可以不写
            return
        for i in range(startIndex, len(nums)):
            if(i>startIndex and nums[i] == nums[i-1] and not used[i-1]):
                continue#去重
            self.path.append(nums[i])
            used[i] = True
            self.backtracking(nums, i+1, used)
            used[i] = False
            self.path.pop()
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()#别忘了排序
        used = [False]*len(nums)
        self.backtracking(nums, 0, used)
        return self.result
        

参考文章

  1. https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2249012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“harmony”整合不同平台的单细胞数据之旅

其实在Seurat v3官方网站的Vignettes中就曾见过该算法&#xff0c;但并没有太多关注&#xff0c;直到看了北大张泽民团队在2019年10月31日发表于Cell的《Landscap and Dynamics of Single Immune Cells in Hepatocellular Carcinoma》&#xff0c;为了同时整合两类数据&#xf…

贴代码PasteForm框架之框架核心帮助类PasteFormHelper说明

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

杂7杂8学一点之ZC序列

重要的放在前面&#xff0c;优秀文章链接&#xff1a;5GNR漫谈13&#xff1a;Zadoff –Chu&#xff08;ZC&#xff09;序列性质 目录 1. ZC序列 1.1 ZC序列的表达式 1.2 ZC序列的特点 2. PRACH中的ZC序列 2.1 为什么要有逻辑根序列与物理根序列的概念 1. ZC序列 ZC序列&…

matlab代码--卷积神经网络的手写数字识别

1.cnn介绍 卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一种深度学习的算法&#xff0c;在图像和视频识别、图像分类、自然语言处理等领域有着广泛的应用。CNN的基本结构包括输入层、卷积层、池化层&#xff08;Pooling Layer&#xff09;、全连…

【Linux】—简单实现一个shell(myshell)

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦&#xff01; 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&…

基于 Flask 和 RabbitMQ 构建高效消息队列系统:从数据生成到消费

简介 在构建 Web 应用时&#xff0c;处理和传输大量数据是不可避免的。对于需要高效、可扩展的消息处理和异步任务执行的场景&#xff0c;使用 RabbitMQ&#xff08;一种流行的消息队列中间件&#xff09;与 Flask&#xff08;一个轻量级的 Python Web 框架&#xff09;结合&a…

Linux:文件管理(一)——文件描述符fd

目录 一、文件基础认识 二、C语言操作文件的接口 1.> 和 >> 2.理解“当前路径” 三、相关系统调用 1.open 2.文件描述符 3.一切皆文件 4.再次理解重定向 一、文件基础认识 文件 内容 属性。换句话说&#xff0c;如果在电脑上新建了一个空白文档&#xff0…

机器学习模型——线性回归

文章目录 前言1.基础概念2.代价函数3.单变量线性回归3.1加载数据3.2初始化超参数3.3梯度下降算法3.3.1初次梯度下降3.3.2 多次梯度下降3.3.3结果可视化 前言 随着互联网数据不断累积&#xff0c;硬件不断升级迭代&#xff0c;在这个信息爆炸的时代&#xff0c;机器学习已被应用…

如何安全高效地打开和管理动态链接库(DLL)?系统提示dll丢失问题的多种有效修复指南

动态链接库&#xff08;DLL&#xff09;文件是Windows操作系统中非常重要的一部分&#xff0c;它们包含了程序运行所需的代码和数据。当系统提示DLL文件丢失时&#xff0c;可能会导致应用程序无法正常运行。以下是一些安全高效地打开和管理DLL文件以及修复DLL丢失问题的方法&am…

数据结构(初阶7)---七大排序法(堆排序,快速排序,归并排序,希尔排序,冒泡排序,选择排序,插入排序)(详解)

排序 1.插入排序2.希尔排序3.冒泡排序4.选择排序(双头排序优化版)5.堆排序6.快速排序1). 双指针法2).前后指针法3).非递归法 7.归并排序1).递归版本(递归的回退就是归并)2).非递归版本(迭代版本) 计算机执行的最多的操作之一就有排序&#xff0c;排序是一项极其重要的技能 接下…

【JavaEE初阶 — 网络原理】初识网络原理

目录 1. 网络发展史 1.1 独立模式 1.2 网络互连 1.2.1 网络互联的背景 1.2.2 网络互联的定义 1.3 局域网LAN 1.4 广域网WAN 2. 网络通信基础 2.1 IP地址 2.2 端口号 2.3 认识协议 2.4 五元组 2.5 协议分层 2.5.1 分…

【C++习题】15.滑动窗口_串联所有单词的子串

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 30. 串联所有单词的子串 题目描述&#xff1a; 解法 滑动窗口哈希表 这题和第14题不同的是&#xff1a; 哈希表不同&#xff1a;hash<string,int>left与right指…

【学术讲座】视觉计算中的深度学习方法 AIGC图像视频生成模型的推理加速

视觉计算中的深度学习方法 发展历程 backbone 强化学习、LLM等&#xff1a;有监督 && 无监督的结合 目标检测 图像分割 网络结构搜索 搜索方法 1&#xff1a;强化学习 2&#xff1a;强化学习 3&#xff1a;梯度算法 结构选择的作用 1&#xff1a;开放环境感知网络…

【VLANPWN】一款针对VLAN的安全研究和渗透测试工具

关于VLANPWN VLANPWN是一款针对VLAN的安全研究和渗透测试工具&#xff0c;该工具可以帮助广大研究人员通过对VLAN执行渗透测试&#xff0c;来研究和分析目标VLAN的安全状况。该工具专为红队研究人员和安全学习爱好者设计&#xff0c;旨在训练网络工程师提升网络的安全性能&…

机器学习之数据预处理理论——基于表格数据分析

一、机器学习中数据预处理的作用与目的 对于机器学习而言&#xff0c;数据预处理是指在数据挖掘、数据分析、模型构建训练等过程中&#xff0c;对原始数据进行一系列的处理&#xff0c;以提高数据质量、减少噪声、提取有用信息等。数据预处理的主要目的是将原始数据转换为有用的…

如何写出好证明(支持思想的深入数学写作)

不断的修改和精炼是写作过程中的重要环节&#xff0c;数学写作最终目的是提供对问题的深刻洞察而非仅仅陈述细节。 根据harvey mudd college Francis Su教授的《GUIDELINES FOR GOOD MATHEMATICAL WRITING》讲稿&#xff0c;总结出撰写好的数学证明需要注意以下几个要点&#x…

中英双语介绍DeepSpeed 的 ZeRO 优化

DeepSpeed 的 ZeRO 优化&#xff1a;通俗易懂的原理与实践指南 引言 在深度学习的大规模模型训练中&#xff0c;显存瓶颈是常见的挑战。DeepSpeed 提供了革命性的 ZeRO (Zero Redundancy Optimizer) 优化技术&#xff0c;为大模型训练节省显存、提高效率提供了强有力的工具。…

如何将 GitHub 私有仓库(private)转换为公共仓库(public)

文章目录 如何将 GitHub 私有仓库转换为公共仓库步骤 1: 登录 GitHub步骤 2: 导航到目标仓库步骤 3: 访问仓库设置步骤 4: 更改仓库可见性步骤 5: 确认更改步骤 6: 验证更改注意事项 如何将 GitHub 私有仓库转换为公共仓库 在软件开发领域&#xff0c;GitHub 是一个广受欢迎的…

【webrtc】 mediasoup中m77的IntervalBudget及其在AlrDetector的应用

IntervalBudget 用于带宽控制和流量整形 mediasoup中m77 代码的IntervalBudget ,版本比较老IntervalBudget 在特定时间间隔内的比特预算管理,从而实现带宽控制和流量整形。 一。 pacedsender 执行周期: 下一次执行的时间的动态可变的 int64_t PacedSender::TimeUntilNextPr…

Z2400023基于Java+Servlet+jsp+mysql的酒店管理系统的设计与实现 源码 调试 文档

酒店管理系统的设计与实现 1.摘要2.主要功能3. 项目技术栈运行环境 4.系统界面截图5.源码获取 1.摘要 本文介绍了一个基于Java的酒店管理系统&#xff0c;该系统采用Servlet、JSP、JDBC以及c3p0等技术构建&#xff0c;为酒店提供了一个全面的管理平台。该系统不仅适合酒店进行…