代码随想录第28天 | 93.复原IP地址 、 78.子集 、 90.子集II

一、前言:

参考文献:代码随想录

今天的主题内容是回溯算法,这一章的干货很多,我需要慢慢的品味,不单单只是表象,还需要研究深层原理。

二、复原IP地址

1、思路:

(1)首先还是确定返回值和参数:

void backtracking(string &s, int startIndex, int pointSum)

这里比往常多了一个pointSum,这个是来判断是否符合ip格式的一个标志,也就是记录这个s中存在多少个".";

(2)终止条件如下:

// pointsum是用来判断这个字符串中存在多少个"."如果有了三个,就说明满足IP格式了if (pointSum == 3) {if (isValud(s, startIndex, s.size() - 1)) {// 这里还有一个条件就是判断最后的一段是否符合IP要求result.push_back(s);}return;} 

这里首先要判断是否有三个”.“,存在之后,再判断最后的那一段是否符合IP的格式,然后才能插入,如果不符合那就直接return回溯了。

(3)单层递归逻辑:

for (int i = startIndex; i < s.size(); i++) {if (isValud(s, startIndex, i)) {s.insert(s.begin() + i + 1, '.'); // 插入"."pointSum++;backtracking(s, i + 2, pointSum); // 这里是 i+2 此逻辑是因为加了"."需要多加一个1// 回溯pointSum--;s.erase(s.begin() + i + 1); // 删除"."} else {break;}}

看起来并不复杂,但是,难疑点比较多。首先就是先判断当前的这个切片处是否符合IP格式,然后再进行插入逗点,pointSum再做记录,然后就可以开始递归了,这里的是 i+2的,因为这个时候插入了逗点,所以需要后移一位,接着就是回溯了。

(4)主函数中存在一个小小的剪枝操作,如下:

if (s.size() < 4 || s.size() > 12) return result;

(5)判断是否为ip的函数为:

    bool isValud(string &s, int start, int end) {if (start > end) {return false;}// 头号字符不能为0(只有一位时可以)if (s[start] == '0' && start != end) {return false;}// 小于等于255int 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) {return false;}}return true;}

这里的细节也比多:

1、start和end的比较;

2、头数字不为0,且不是只有一个数字;

3、和小于等于255;

2、整体代码如下:

class Solution {
private:// 判断是否为合法IPbool isValud(string &s, int start, int end) {if (start > end) {return false;}// 头号字符不能为0(只有一位时可以)if (s[start] == '0' && start != end) {return false;}// 小于等于255int 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) {return false;}}return true;}vector<string> result;void backtracking(string &s, int startIndex, int pointSum) { // pointsum是用来判断这个字符串中存在多少个"."如果有了三个,就说明满足IP格式了if (pointSum == 3) {if (isValud(s, startIndex, s.size() - 1)) {// 这里还有一个条件就是判断最后的一段是否符合IP要求result.push_back(s);}return;} // 单层递归逻辑for (int i = startIndex; i < s.size(); i++) {if (isValud(s, startIndex, i)) {s.insert(s.begin() + i + 1, '.'); // 插入"."pointSum++;backtracking(s, i + 2, pointSum); // 这里是 i+2 此逻辑是因为加了"."需要多加一个1// 回溯pointSum--;s.erase(s.begin() + i + 1); // 删除"."} else {break;}}}
public:vector<string> restoreIpAddresses(string s) {if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了backtracking(s, 0 , 0);return result;}
};

 三、子集

1、思路:

(1)返回值和终止条件并没有什么改变:

void backtracking(vector<int> &nums, startIndex)

(2)终止条件(这个条件可有可不有,因为在return时以及到了叶子节点处,循环自然就不去了,就不用手动终止了):

if (startIndex >= nums.size()) return;

(3)单层递归逻辑:

for (int i = startIndex; i < nums.size(); i++) {// 插入元素path.push_back(nums[i]);// 递归backtracking(nums, i + 1);// 回溯path.pop_back();}

还是插入,递归,回溯。。。

(4)最重要的就是收集path,在每次递归开始时就可以收集子集了;

2、整体代码如下:

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;}
};

 四、子集||

1、思路:

这个题目和上一题加上组合总和|||综合,这里也需要添加一个used来判断是否使用了这个元素,如果使用了那就可以继续遍历,说明在树枝上,但是如前面一个元素相同,但是没有被使用,说明在数层上面,就需要跳过这个数字了,避免重复。

图解如下:

 

 

这里就不一步步分析了;

2、整体代码如下:

class Solution {
private:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& nums, int startIndex, vector<bool> &used) {result.push_back(path);for (int i = startIndex; i < nums.size(); i++) {if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {continue;}path.push_back(nums[i]);used[i] = true;backtracking(nums, i + 1, used);used[i] = false;path.pop_back();}return;}
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;}
};

今日学习时间:2小时

leave message:

Her behavior is well-accorded with the expectations of her parents.

她的行为与父母的期望相符。 

 

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS 应用开发之同步任务开发指导 (TaskPool和Worker)

同步任务是指在多个线程之间协调执行的任务&#xff0c;其目的是确保多个任务按照一定的顺序和规则执行&#xff0c;例如使用锁来防止数据竞争。 同步任务的实现需要考虑多个线程之间的协作和同步&#xff0c;以确保数据的正确性和程序的正确执行。 由于TaskPool偏向于单个独…

晚间兼职攻略:六个副业轻松上手

晚上兼职副业&#xff0c;作为增加额外收入的途径&#xff0c;选择多样且灵活。以下是六个特别适合晚上进行的副业&#xff0c;让你在闲暇时光也能充实自我&#xff0c;获得收益。 1&#xff0c;网络调查与市场研究是一个值得考虑的选项。你可以在晚上抽出空闲时间&#xff0c…

DEM高程数字模型制作技术分享

1. 引言 ​数字高程模型&#xff08;Digital Elevation Model&#xff0c;简称DEM&#xff09;是地形表面地形特征的数字表示。它提供了关于地面起伏、地形形态、地表特征等重要信息。在地理信息系统&#xff08;GIS&#xff09;、遥感、地质学、水利工程等领域&#xff0c;DEM…

群晖NAS使用Docker部署大语言模型Llama 2结合内网穿透实现公网访问本地GPT聊天服务

文章目录 1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 随着ChatGPT 和open Sora 的热度剧增,大语言模型时代,开启了AI新篇章,大语言模型的应用非常广泛&#xff0c;包括聊天机…

《信息技术服务 智能运维 第2部分:数据治理》国家标准2024年第一次线下编写会议成功召开

2024年3月13日~15日&#xff0c;由运维数据治理国标编制组主办的运维数据治理国家标准2024年第一次编写工作会议在上海成功召开。 本次会议由云智慧&#xff08;北京&#xff09;科技有限公司承办&#xff0c;来自南网数字集团信通公司、太保科技、平安银行、广发银行、广东农…

【电源专题】电池不均衡的影响与原因

在使用多节电池设计产品时,大家都知道如果多节电池不均衡会影响电池寿命与充电安全。特别是在充电末端与放电末端时表现较为明显。 电池不均衡的影响 那么为什么会影响安全与寿命呢?其原因如下: 如果电池不均衡时,相当于木桶的短板效应。一方面没法充满,充电时电压高的那一…

透明天气超实用工具更便捷地查看本地天气情况!

确切的气象数据播报&#xff0c;支持分钟级的降雨预测&#xff0c;精选的数百万张美丽城市背景图片和精美的风景图片&#xff0c;满足您与数百万朋友分享美丽天气的需求&#xff0c;用户友好的设计&#xff0c;简洁的界面布局&#xff0c;轻松查询天气信息的同时&#xff0c;还…

【论文笔记】Text2QR

论文&#xff1a;Text2QR: Harmonizing Aesthetic Customization and Scanning Robustness for Text-Guided QR Code Generation Abstract 二维码通常包含很多信息但看起来并不美观。stable diffusion的出现让平衡扫描鲁棒性和美观变为可能。 为了保证美观二维码的稳定生成&a…

06 | Swoole 源码分析之 Coroutine 协程模块

首发原文链接&#xff1a;Swoole 源码分析之 Coroutine 协程模块 大家好&#xff0c;我是码农先森。 引言 协程又称轻量级线程&#xff0c;但与线程不同的是&#xff1b;协程是用户级线程&#xff0c;不需要操作系统参与。由用户显式控制&#xff0c;可以在需要的时候挂起、或…

分享一种快速移植OpenHarmony Linux内核的方法

移植概述 本文面向希望将 OpenHarmony 移植到三方芯片平台硬件的开发者&#xff0c;介绍一种借助三方芯片平台自带 Linux 内核的现有能力&#xff0c;快速移植 OpenHarmony 到三方芯片平台的方法。 移植到三方芯片平台的整体思路 内核态层和用户态层 为了更好的解释整个内核…

曲线降采样之道格拉斯-普克算法Douglas–Peucker

曲线降采样之道格拉斯-普克算法Douglas–Peucker 该算法的目的是&#xff0c;给定一条由线段构成的曲线&#xff0c;找到一条点数较少的相似曲线&#xff0c;来近似描述原始的曲线&#xff0c;达到降低时间、空间复杂度和平滑曲线的目的。 附赠自动驾驶学习资料和量产经验&…

通过提交容器的方式修改ubuntu镜像的apt源

通过提交容器的方式修改ubuntu镜像的apt源 步骤总结 问题&#xff0c;每次创建容器之后&#xff0c;都要在容器内手动更改镜像源。 不如&#xff0c;干脆修改镜像的apt源&#xff0c;一次到位。 步骤 先创建一个容器&#xff0c;到容器内执行变更命令。 D:/sandbox> dock…

【Vue】vue3简介与环境配置

文章目录 项目编码规范什么是 Vue&#xff1f;安装node环境nvm针对node版本惊醒管理的工具 项目编码规范 组合式API Typescript setup(语法糖) 什么是 Vue&#xff1f; Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;…

【SQL】1633. 各赛事的用户注册率(COUNT函数 表达式用法)

题目描述 leetcode题目&#xff1a;1633. 各赛事的用户注册率 Code select contest_id, round(count(*)/(select count(*) from Users)*100, 2) as percentage from Register group by contest_id order by percentage desc, contest_id ascCOUNT()函数 COUNT函数用法&#…

docker容器之etcd安装

一、etcd介绍 1、etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。 2、etcd特点 简单的接口&#xff0c;通过标准的HTTP API进行调用&#xff0c;也可以使用官方提供的 etcdctl 操作存储的数据。…

1999-2022年上市公司员工人数数据

1999-2022年上市公司员工人数数据 1、时间&#xff1a;1999-2022年 2、指标&#xff1a;证券代码、时间、员工人数 3、来源&#xff1a;整理自csmar 4、范围&#xff1a;上市公司 5、指标解释&#xff1a; 上市公司员工人数是衡量公司规模和发展状的重要指标。该数据直接…

编程新手必看,python中的转义字符及注释!(4)

1、常见的转义字符 Python中的转义字符用于在字符串中表示一些特殊的字符&#xff0c;这些字符通常无法直接输入或具有特殊的意义。以下是一些常见的转义字符及其含义&#xff1a; 在Python中&#xff0c;可以使用转义字符来表示一些特殊的字符。以下是使用转义字符的几种常见…

VuePress基于 Vite 和 Vue 构建优秀框架

VitePress 是一个静态站点生成器 (SSG)&#xff0c;专为构建快速、以内容为中心的站点而设计。简而言之&#xff0c;VitePress 获取用 Markdown 编写的内容&#xff0c;对其应用主题&#xff0c;并生成可以轻松部署到任何地方的静态 HTML 页面。 VitePress 附带一个用于技术文档…

Java复习第十六天学习笔记(JSP、Servlet),附有道云笔记链接

【有道云笔记】十六 4.2 JSP、Servlet https://note.youdao.com/s/QccA5g1G 一、软件的结构 C/S (Client - Server 客户端-服务器端) 典型应用&#xff1a;QQ软件 &#xff0c;飞秋&#xff0c;印象笔记。 特点&#xff1a; 必须下载特定的客户端程序。服务器端升级&#…

保护Android应用安全:全面探究代码混淆在加固中的作用

Android APP 加固是优化 APK 安全性的一种方法&#xff0c;常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码 使用 ipaguard工具可以对代码进行混淆&#xff0c;使得反编译出来的代码很难阅读和理解&#xff…