Studying-代码随想录训练营day24| 93.复原IP地址、78.子集、90.子集II

news2025/1/21 5:52:19

第24天,回溯算法part03,牢记回溯三部曲,掌握树形结构结题方法💪

目录

93.复原IP地址

78.子集

90.子集II

总结 


93.复原IP地址

文档讲解:代码随想录复原IP地址

视频讲解:手撕复原IP地址

题目:

学习:本题属于切割类问题,不同的是本题需要使用 ' · ’ 来切割,并且本题对切割的数字大小和多少,切割多少次都有要求。但本质都是两步:1.切割;2.判断切割是否正确。

依据以上两点,本题和131.分割回文串不同的地方就在于对分割部分的判断和终止条件的选择。回溯逻辑用树形结构来表示为:

注意:判断分割部分是否合法,主要从三个部分出发:1.段位以0为开头且不止有0的数字不合法。2.段位里有非正整数字符不合法。3.段位如果大于255了不合法。

代码:确定回溯三部曲,注意本题要在字符串中加入' . ' 因此回溯的时候要删掉该点。

//时间复杂度O(3^4)
//空间复杂度O(n)
class Solution {
public:
    //直接在字符串上进行操作,因此不设置路径数组
    vector<string> result; //返回数组
    //确定返回值和参数列表,直接在答案数组中插入因此不需要返回值,参数中需要原字符串s,分割点startindex
    //本题还需要一个int型变量point表示当前逗号的数量
    void backtracking(string& s, int startindex, int point) {
        //确定终止条件,当逗号数量为3个时,说明当前分割已经完成了
        if(point == 3) {
            //最后一部分字符串还需要进行判断
            if(ipvaild(s, startindex, s.size() - 1)) {
                result.push_back(s);
            }
            return;
        }

        //确定单层递归逻辑
        for(int i = startindex; i < s.size(); i++) {
            //startindex作为切割线,切割的字符串区间为[startindex, i],左闭右闭
            //判断切割下来的字符串是否合理
            if(ipvaild(s, startindex, i)){
                //如果合理的话,在字符串下标i后插入逗号,并进行下一轮递归
                s.insert(s.begin() + i + 1, '.');
                point++;
                //注意这里需要传入的是i+2,因为加了一个逗号,切割的位置需要往后移两位
                backtracking(s, i + 2, point);
                point--; //回溯
                s.erase(s.begin() + i + 1);
            }
            else {  //假如不满足,后续的切割方法也难以满足,直接跳出本层循环
                break;
            }
        }
    }
    bool ipvaild(string& s, int start, int end) {
        if (start > end) {
            return false;
        }
        //如果存在前置0的话,返回false
        if(start != end && s[start] == '0') {
            return false;
        }
        int num = 0; //对切割字符串进行求和
        for(int i = start; i <= end; i++) {
            if(s[i] - '0' < 0 || s[i] - '0' > 9) {
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if(num > 255) {
                return false;
            }
        }
        return true;
    }
    vector<string> restoreIpAddresses(string s) {
        backtracking(s, 0, 0);
        return result;
    }
};

本题可以进行剪枝,自认为本题可以从三个部分进行剪枝,分别是:1.剪枝1,给的字符串不满足切割有效的IP地址;2.剪枝2,分割实际只需要分割3个字符就行,缩小循环范围;3.每次切割后可以判断一下是否后面的字符还能够满足切割要求。

代码:

class Solution {
public:
    //切割问题主要需要两点:切割,判断!
    //直接在字符串上进行操作,因此不设置路径数组
    vector<string> result; //返回数组
    //确定返回值和参数列表,直接在答案数组中插入因此不需要返回值,参数中需要原字符串s,分割点startindex
    //本题还需要一个int型变量point表示当前逗号的数量
    void backtracking(string& s, int startindex, int point) {
        //确定终止条件,当逗号数量为3个时,说明当前分割已经完成了
        if(point == 3) {
            //最后一部分字符串还需要进行判断
            if(ipvaild(s, startindex, s.size() - 1)) {
                result.push_back(s);
            }
            return;
        }

        //确定单层递归逻辑
        //剪枝2,分割只需要分割3个数字就够了
        for(int i = startindex; i < startindex + 3; i++) {
            //剪枝3,后续剩余的节点数不满足切割要求
            if(s.size() - startindex > (4 - point) * 3 || s.size() - startindex < (4 - point)) {
                break;
            }
            //startindex作为切割线,切割的字符串区间为[startindex, i],左闭右闭
            //判断切割下来的字符串是否合理
            if(ipvaild(s, startindex, i)){
                //如果合理的话,在字符串下标i后插入逗号,并进行下一轮递归
                s.insert(s.begin() + i + 1, '.');
                point++;
                //注意这里需要传入的是i+2,因为加了一个逗号,切割的位置需要往后移两位
                backtracking(s, i + 2, point);
                point--; //回溯
                s.erase(s.begin() + i + 1);
            }
            else {  //假如不满足,后续的切割方法也难以满足,直接跳出本层循环
                break;
            }
        }
    }
    bool ipvaild(string& s, int start, int end) {
        if (start > end) {
            return false;
        }
        //如果存在前置0的话,返回false
        if(start != end && s[start] == '0') {
            return false;
        }
        int num = 0; //对切割字符串进行求和
        for(int i = start; i <= end; i++) {
            if(s[i] - '0' < 0 || s[i] - '0' > 9) {
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if(num > 255) {
                return false;
            }
        }
        return true;
    }
    vector<string> restoreIpAddresses(string s) {
        //剪枝1,给的字符串不满足切割有效的ip地址
        if(s.size() < 4 || s.size() > 12) return result;
        backtracking(s, 0, 0);
        return result;
    }
};

78.子集

文档讲解:代码随想录子集

视频讲解:手撕子集问题

题目:

学习:回溯算法能够解决的第三类问题,子集问题。子集问题与切割问题和组合问题的本质不同在于,切割问题和组合问题都是在叶子节点收获结果,但是子集问题需要在每个节点都收获结果,这也导致了子集问题对result数组push_back的位置不同,但其他部分其实几乎是一致的。子集问题其实也能看作是一个组合问题,因此也需要注意去重。回溯逻辑转化为树形结构为:

代码:确定回溯三部曲

//时间复杂度O(n*2^n)
//空间复杂度O(n)
class Solution {
public:
    vector<vector<int>> result; //返回数组
    vector<int> path; //保存路径
    //确定返回值和参数列表,在数组中直接进行操作,所以不需要返回值,参数列表需要遍历的数组和当前遍历的下标
    void backtracking(vector<int>& nums, int startindex) {
        //子集问题的不同在于,子集收获答案是在每个节点均收货一次
        //在终止条件前,先进行收获,其中也包含了空集
        result.push_back(path);
        //确定终止条件(其实等于就可以了),遍历到最后
        //该终止条件也可以不写,因为当startindex >= nums.size()时,下面的for循环也不会进入,但要注意for循环后加return。
        if(startindex >= nums.size()) {
            return;
        }

        //确定单层递归逻辑
        for(int i = startindex; i < nums.size(); i++) {
            path.push_back(nums[i]);
            //传入i+1,防止出现重复
            backtracking(nums, i + 1);
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums, 0);
        return result;
    }
};

90.子集II

文档讲解:代码随想录子集II

视频讲解:手撕子集II

题目:

学习:本题和上一题不同点在于本题存在重复元素,需要对后续的相同元素进行去重,事实上本题和组合总和II的去重是相同的,本质都是如果后面出现了与前面相同的元素就可以跳过该元素的遍历,因为前面的元素一定把后面的元素还有的组合都包括的。基于此本题可以采取和40.组合总和II相同的去重方式,都是在树层进行去重

代码:确定回溯三部曲

//时间复杂度O(n*2^n)
//空间复杂度O(n)
class Solution {
public:  
    vector<vector<int>> result; //返回答案数组
    vector<int> path; //保存路径
    //确定参数和返回值
    void backtracking(vector<int>& nums, int startindex) {
        //收集每一个节点
        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]){
                continue;
            }
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        //进行排序,便于去重
        sort(nums.begin(), nums.end());
        backtracking(nums, 0);
        return result;
    }
};

总结 

切割问题首尾,子集问题开始,牢记子集问题和切割问题和组合问题的不同。

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

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

相关文章

前端小白必学:对Cookie、localStorage 和 sessionStorage 的简单理解

前言 Cookie、localStorage 和 sessionStorage 作为Web开发领域中广泛采用的三种客户端数据存储技术&#xff0c;它们各自拥有独特的优势、应用场景及限制条件&#xff0c;共同支撑起前端数据管理的多样化需求。也是面试常考题之一&#xff0c;今天就和大家简单谈一下我对它们…

什么是TOGAF架构框架的ADM方法?

ADM是架构开发方法&#xff08; Architecture Development Method&#xff09;&#xff0c;为开发企业架构所要执行的各个步骤以及它们质检的关系进行详细的定义&#xff0c;它是TOGAF规范中最为核心的内容。 ADM的具体步骤&#xff1a; 预备阶段&#xff08;Preliminary Phas…

Redis 高可用(理论)

目录 Redis 高可用 Redis 持久化 RDB 持久化 触发条件 手动触发 自动触发 ##其他自动触发机制## 执行流程 启动时加载 AOF 持久化 执行流程 &#xff08;1&#xff09;命令追加(append) &#xff08;2&#xff09;文件写入(write)和文件同步(sync) &#xff08;3&…

ThreadPoolExecutor 线程回收时机详解

个人博客 ThreadPoolExecutor 线程回收时机详解 | iwts’s blog 总集 想要完整了解下ThreadPoolExecutor&#xff1f;可以参考&#xff1a; 基于源码详解ThreadPoolExecutor实现原理 | iwts’s blog Worker-工作线程管理 线程池设计了内部类Worker&#xff0c;主要是用来…

AI agent是什么,什么技术栈

AI agent&#xff0c;也称为会话代理或聊天机器人&#xff0c; 是一种通过文本或语音模拟人类对话的计算机程序。 它们旨在以自然且引人入胜的方式理解和响应用户输入。 AI agent 被广泛用于各种应用中&#xff0c;包括客户服务、营销、 销售和教育。 有两种主要类型的 AI agen…

2.linux操作系统CPU使用率和平均负载区别

目录 概述cpu使用率区别 结束 概述 linux操作系统CPU 使用率 和 平均负载 区别 负载高并不一定使用率高&#xff0c;有可能 cpu 被占用&#xff0c;但不干活。 cpu使用率 cpu使用率&#xff1a;cpu非空闲态运行的时间占比&#xff0c;反映cpu的繁忙程度&#xff0c;和平均负载…

DS18B20单总线数字温度传感器国产替代MY18E20 MY1820 MY18B20Z MY18B20L(一)

前言 DS18B20是全球第一个单总线数字温度传感器&#xff0c;推出时间已经超过30年&#xff0c;最早由美国达拉斯半导体公司推出&#xff0c;2001年1月&#xff0c;美信以25亿美元收购达拉斯半导体&#xff08;Dallas Semiconductor&#xff09;&#xff0c;而美信在2021年8月被…

使用vscode+git+github管理代码

一、打开代码所在的文件夹 以我最近的看的一个代码项目为例 打开如下 为了方便日后打开&#xff0c;可以把经常看的代码拉出来&#xff0c;然后建一个工作区&#xff0c;后续查看也方方便。直接点开下面第二张图的工作区文件就可以。 二、将代码上传到github 会自动创建一个同名…

成为画图大师,用图表讲故事

这些问题你是否遇到过: 项目总结会上&#xff0c;如果用数据呈现你做的价值&#xff1f; 完善详尽的数据分析得出了让人信服的结论&#xff0c;如何呈现在BOSS面前? 我们要的不是数据&#xff0c;而是数据告诉我们的事实 数据很重要&#xff0c;但只是原料&#xff0c;所以…

分治精炼宝库-----快速排序运用(⌯꒪꒫꒪)੭

目录 一.基本概念: 一.颜色分类&#xff1a; 二.排序数组&#xff1a; 三.数组中的第k个最大元素&#xff1a; 解法一&#xff1a;快速选择算法 解法二&#xff1a;简单粗暴优先级队列 四.库存管理Ⅲ&#xff1a; 解法一&#xff1a;快速选择 解法二&#xff1a;简单粗…

Tcmalloc工具定位内存泄漏问题

内存泄漏问题定位 gperftools工具安装 执行如下操作&#xff1a; git clone https://github.com/gperftools/gperftools.git 注&#xff1a;如果网速较慢&#xff0c;可直接去下载压缩包。 如我下载的地址&#xff1a;https://github.com/gperftools/gperftools/releases/ta…

Unity动画系统(1)

6.1 动画系统基础1-5_哔哩哔哩_bilibili 模型信息 Generic非人型 Configure 虚线圈可以没有&#xff0c;实线圈必须有&#xff0c;15个骨骼是必须的 p313 尾巴、翅膀属于非人型 p314 一般使用create from this model 游戏对象不再旋转 游戏对象不再发生位移 调整中心位置

八月份的护网行动如何参加?

护网行动背景 什么是“护网行动”&#xff1f; 指挥机构∶由公安机关统一组织的"网络安全实战攻防演习"。 护网分为两级演习∶公安部对总部&#xff0c;省厅对省级公司。 什么是“实战攻防演习” 每支队伍3-5 人组成&#xff0c;明确目标系统&#xff0c;不限制攻…

Class Constructors and Destructors (类的构造函数和析构函数)

Class Constructors and Destructors [类的构造函数和析构函数] 1. Declaring and Defining Constructors (声明和定义构造函数)2. Using Constructors (使用构造函数)3. Default Constructors (默认构造函数)4. Destructors (析构函数)5. Improving the Stock Class (改进 Sto…

使用 privacyIDEA 实现 Windows RDP 多因素认证 (MFA)

前言 在等保 2.0 标准中有要求: d&#xff09;应采用口令、密码技术、生物技术等两种或两种以上组合的鉴别技术对用户进行身份鉴别&#xff0c;且其中一种鉴别技术至少应使用密码技术来实现。 可以借助开源的 privacyIDEA 配合 AD 域环境实现 RDP MFA 认证登录以满足上面的要…

docker安装rocketMq5x以上的版本

1.背景 安装RocketMQ 5.x以上的版本主要是因为新版本引入了许多性能优化、新功能以及对已有特性的增强&#xff0c;这些改进可以帮助提升消息队列系统的稳定性和效率。 1.性能提升&#xff1a;RocketMQ 5.x版本通常包括了对消息处理速度、吞吐量和延迟的优化&#xff0c;使得系…

大模型压缩-LoRAP

这里写目录标题 1.多头注意力和FFN的权重分布2 多头矩阵的低秩分解FFN无梯度通道剪枝 这篇文章 1期望找到一个“剪枝&#xff0b;低秩分解”的路子&#xff0c;使结构化剪枝达到非结构化剪枝的性能。 1.多头注意力和FFN的权重分布 Fig. 1.1 多头注意力权重矩阵 从Fig.1.1可以看…

万字浅析视频搜索系统中的多模态能力建设

万字浅析视频搜索系统中的多模态能力建设 FesianXu 20240331 at Tencent WeChat search team 前言 视频搜索是天然的富媒体检索场景&#xff0c;视觉信息占据了视频的一大部分信息量&#xff0c;在视频搜索系统中引入多模态能力&#xff0c;对于提高整个系统的能力天花板至关重…

学习感悟丨在誉天学习数通HCIP怎么样

大家好&#xff0c;我是誉天学员的徐同学&#xff0c;学习的数通HCIP课程。 在学校的时候&#xff0c;听说下半年就要出去实习了&#xff0c;心中坎坷不安&#xff0c;现在我学到的知识远远不够的。然后就想着学点东西充实一下自己的知识面和专业能力&#xff0c;有一次和同学谈…

【STM32嵌入式系统设计与开发---传感器拓展】——1_4_标准库FreeRTOS移植实验

目录 雅俗理解源码下载链接知识拓展步骤1&#xff1a;stm32f103vet6移植freeRTOS步骤:&#xff08;1&#xff09;准备开发环境&#xff08;2&#xff09;添加FreeRTOS移植 致谢 雅俗理解 雅&#xff1a;FreeRTOS是一个开源的实时操作系统&#xff08;RTOS&#xff09;&#xf…