当前位置: 首页 > news >正文

【算法练习Day23】 复原 IP 地址子集子集 II

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 复原 IP 地址
  • 子集
  • 子集 II
  • 总结:

复原 IP 地址

93. 复原 IP 地址 - 力扣(LeetCode)
在这里插入图片描述

复原IP地址这道题也是一道切割字符串的问题,也是略有难度的一道题,起初我做的时候,想不通是怎么精确的把字符串分割成四段做终止条件的,后来看了题解知道,并不是一开始就能够确定切出多大一块,而是一点点试错的,虽然我们知道,是要将该字符串序列分成四份,由三个点分割开来,但是我们代码实现时候是无法做到一开始就确定前半部分是切割前几个数字的,这是因为字符串序列可能是不一样的,题目要求数字前面不能由前导0构成,只有0是可以的,且每一块分割出来的数字大于等于0小于等于255,由于字符序列的不同,有的时候我们第一次只能切一个数字,就是0的情况,0不能做前导,有的时候我们可以多切一点,这是无法固定的,所以我们要一点点切割递归下去,好在我们有函数递归可以帮助我们完成这一难题。

其他的困难部分我们在上一期的切割回文子串已经讲的差不多了,无非也就是如何表示切割线,如何传进去切割区间做判断,不明白可以去看上一期。

区别在于,这道题的终止判断条件也是有所不同的,它的终止条件是我们已经放入了三个逗点做分割了,这时候我们进入终止判断,分割问题,通常都是由题目要求的关键信息,作为终止条件,它和这几期做的那些组合题不一样,不是固定的套路,需要自行想出。

class Solution {
private:vector<string> result;// 记录结果// startIndex: 搜索的起始位置,pointNum:添加逗点的数量void backtracking(string& s, int startIndex, int pointNum) {if (pointNum == 3) { // 逗点数量为3时,分隔结束// 判断第四段子字符串是否合法,如果合法就放进result中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)) { // 判断 [startIndex,i] 这个区间的子串是否合法s.insert(s.begin() + i + 1 , '.');  // 在i的后面插入一个逗点pointNum++;backtracking(s, i + 2, pointNum);   // 插入逗点之后下一个子串的起始位置为i+2pointNum--;                         // 回溯s.erase(s.begin() + i + 1);         // 回溯删掉逗点} else break; // 不合法,直接结束本层循环}}// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法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;}
public:vector<string> restoreIpAddresses(string s) {result.clear();if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了backtracking(s, 0, 0);return result;}
};

还有三点需要注意的细节,第一点是除了在for循环里要判断该切割区间是否合法,我们在终止条件还要额外判断一次,这为什么呢?原因在于我们终止条件是三个逗点就插入字符串,而我们之前只是判断了三次切割串是否合法,因为判断一次要放一个标点所以肯定是只判断了三次,我们在这里加一次判断的目的是为了知道,这最后剩余的部分是否依然具有合法性。第二点是字符串的insert成员函数插入标点是传入下标的前一个位置,所以要进行+1传入,而且我们在进行递归下一层时,传入的下一层开始遍历起始位置是i+2,而不是i+1,因为加入了一个标点的缘故。第三点是判断部分代码的细节,下面的for循环来依次取各个数相加判断和是否大于255,其实这里的要点主要在于对每一个字符的判断,防止它是字符1-9之外的数,但是leetcode上已经明确说了传入的都是数字序列,可是题目仍然要求判断,感觉可能是题目描述没有全改过来的缘故。

子集

78. 子集 - 力扣(LeetCode)
在这里插入图片描述

子集问题和前面讲过很多的组合问题,解法如出一辙,只是在处理数据加入结果集里有所不同。

class Solution {
private: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++) {path.push_back(nums[i]);backtracking(nums, i + 1);path.pop_back();}}
public:vector<vector<int>> subsets(vector<int>& nums) {result.clear();path.clear();backtracking(nums, 0);return result;}
};

和组合问题一样,需要注意的是处理数据,是每一次都将节点放入结果数组,因为求的是子集要保留所有的节点,每一个节点都是它的子集,所以不存在剪枝操作。那空集是如何放入的呢?实际上就是没有节点时候直接放入了path,这一点也很好理解。单层递归是用一个for循环这一点就是组合的内容,不懂的可以翻看前面组合的章节。

子集 II

90. 子集 II - 力扣(LeetCode)
在这里插入图片描述

子集II整体代码和子集差不多,只是加入了组合的去重逻辑。

class Solution {
public:vector<vector<int>>result;vector<int>path;void backtraking(vector<int>&nums,int start,vector<int>&nums2){result.push_back(path);for(int i=start;i<nums.size();i++){if(i>=1&&nums[i]==nums[i-1]&&nums2[i-1]==0)continue;nums2[i]=1;path.push_back(nums[i]);backtraking(nums,i+1,nums2);path.pop_back();nums2[i]=0;}}vector<vector<int>> subsetsWithDup(vector<int>& nums) {vector<int>nums2(nums.size(),0);sort(nums.begin(),nums.end());backtraking(nums,0,nums2);return result;}
};

用一个辅助数组记录我们所要添加数的数组,各个数字的加入情况。这里再简单讲一下去重的逻辑,画一个树形图辅助理解,当我们在一个数组里加入元素,这道题说是给定数组有重复元素,当我们构成一个答案数据时候i,由于每次递归会i+1,走到下一个数据位置,作为下一次放元素的起始位置,所以我们不需要担心会一个数据取两次,但是如果有两个数据,我们第一次用到它取的一系列答案数据,再你第二次用到的时候会将这些答案数据又取一次,因为第一次用的这个数字包含了你第二次用的时候取到的全部答案了,这一点画出树形图很容易理解,所以要将它去掉,也就是去重的逻辑,需要做的是将给定数组排序,让重复数据挨在一起,然后用一个数组去辅助做判断,如果本次要放入的数据和上一个位置数据值相等,且上一个相等数据本次没有放入,则说明我们要删除它,这是数层上的去重逻辑。

总结:

今天我们完成了复原 IP 地址、子集、子集 II三道题,相关的思想需要多复习回顾。接下来,我们继续进行算法练习。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

http://www.lryc.cn/news/198806.html

相关文章:

  • fastadmin框架token验证
  • 了解 AI :了解 AI 方面的一些术语 (中英文对照)
  • 【Python学习笔记】对象、方法
  • 企业IT资产设备折旧残值如何计算
  • Linux性能优化--性能工具:下一步是什么
  • 网工内推 | IT主管、高级网工,上市公司,必须持有HCIE认证
  • bulldog 靶机
  • 如何借助边缘智能网关打造智慧城市便民驿站
  • 谈谈电商App的压测
  • ​VsCode修改侧边栏字体大小——用缩放的方法​
  • 基于Java的农资采购销售管理系统设计与实现(源码+lw+部署文档+讲解等)
  • 【AIGC核心技术剖析】扩大富有表现力的人体姿势和形状估计SMPLer-X模型
  • 【C++面向对象】1. 类、对象
  • PAM从入门到精通(十三)
  • Stable Diffusion WebUI几种解决手崩溃的方法
  • kr 第三阶段(一)16 位汇编
  • power point导出pdf保留字体
  • 云务器迁移(腾讯云>华为云)
  • [USACO11MAR] Brownie Slicing G题解(二分+二维前缀和+矩阵分割)
  • 【每日一题】—— B. Arrays Sum (Grakn Forces 2020)
  • XTU-OJ 1328-数码和
  • 混入组件 (mixin)
  • ubuntu18.04 RTX3060 rangnet++训练
  • HZOJ-72:猜拳
  • 【Django 03】QuerySet 和 Instance应用
  • 安装 mysql
  • 文件管理系统的基本认识
  • Excel·VBA制作工资条
  • 【SA8295P 源码分析 (二)】10 - HQX Display(OpenWFD)qcdisplaycfg_ADP_STAR_LA.xml 配置文件解析
  • git操作说明