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

【代码随想录训练营第42期 Day24打卡 回溯Part3 - LeetCode 93.复原IP地址 78.子集 90.子集II

目录

一、做题心得

二、题目与题解

题目一:93.复原IP地址

题目链接

题解:回溯--分割问题

题目二:78.子集

题目链接

题解:回溯--子集问题

题目三:90.子集II

题目链接

题解:回溯--子集问题

三、小结


一、做题心得

今天的题个人感觉第一道 93. 复原 IP 地址 - 力扣(LeetCode)还是挺有难度的,虽然跟昨天打卡的分割回文串很相似,但是自己做的时候还是有点吃力。后边两道题就很简单了,感觉和前两天练的组合问题差不多,个人感觉问题不大。

这里直接开始今天的题目吧。

二、题目与题解

题目一:93.复原IP地址

题目链接

93. 复原 IP 地址 - 力扣(LeetCode)

有效 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 中的任何数字。你可以按 任何 顺序返回答案。

示例 1:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:

输入:s = "0000"
输出:["0.0.0.0"]

示例 3:

输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 1 <= s.length <= 20
  • s 仅由数字组成
题解:回溯--分割问题

这个题也是很明显的分割问题。 、

分析题意:有效IP地址分为4个部分,每一部分由.隔开,每一部分都有限制要求(这个限制要求往往会出现if从句,如果复杂的话需要自定义函数)

关键

1.自定义函数判断IP地址某部分是否有效(即是否符合题目要求)

2.如何截取字符串s的各种子串:substr()函数

3.如何实现剪枝(具体看代码):三处--两处是特殊情况的单独处理,一处是循环遍历对终止条件的缩小

4.终止条件是什么:递归遍历完整个字符串的同时,IP地址恰好被分为4个部分

想清楚上边四点,这道题也就好解决了,剩下的就跟昨天 131. 分割回文串  一个道理。

代码如下:

class Solution {  
public:  vector<string> ans;  vector<string> vec;bool isRange(string substring) {        //判断字符串是否为有效IP地址的一部分if (substring.size() != 1 && substring[0] == '0') {        //前导0无效(如012,023等等)return false;  }  int num = stoi(substring);      //将字符串转化为数字(字符串只包含数字,不考虑负数)return num <= 255;          }   void backtrack(string& s, int start) {    if (vec.size() == 4 && start == s.size()) {     //终止条件:当vec中存储了4个部分,并且刚好遍历完了整个字符串s时,说明找到了一个有效的IP地址string ip = "";  for (int i = 0; i < vec.size(); ++i) {      //vec每一部分结束后添加.(最终结果存放在ip里)ip += vec[i];  if (i < vec.size() - 1) {  ip += ".";  }  }  ans.push_back(ip);    return;  }  if (start == s.size() && vec.size() != 4) {    //剪枝1:当遍历完了整个s但IP地址部分数不为4时,重新返回递归return;}for (int i = start; i < start + 3 && i < s.size(); i++) {   //剪枝2:i < start + 3表示IP地址每一部分不超过三位数string substring = s.substr(start, i - start + 1);     //截取字符串start到i的子串if (!isRange(substring)) {  continue;}  vec.push_back(substring);  backtrack(s, i + 1);      vec.pop_back();  }  }  vector<string> restoreIpAddresses(string s) {  if (s.size() < 4 || s.size() > 12) {       //剪枝3:不可能存在有效IP地址情况直接返回空向量return ans;}backtrack(s, 0);  return ans;  }  
};

题目二:78.子集

题目链接

78. 子集 - 力扣(LeetCode)

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

子集

(幂集)。

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

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同
题解:回溯--子集问题

 子集问题个人感觉跟组合问题差不多,可能最大的不同就在于终止条件那里。

这里我们需要注意了,对于对于子集问题:当我们要得到一个数组集合的全部子集,其实是没有终止条件的(当然,你也可以想成有,就是全部都自然遍历添加完,不过这其实跟没有也没区别),也就是说,我们只需要把每一个递归得到的数组添加到结果里边去即可。这里就要求我们对模板的有效运用了,不要没有终止条件就硬想半天。

代码如下:

class Solution {
public:vector<vector<int>> ans;vector<int> vec;void backtrack(vector<int>& nums, int start) {ans.push_back(vec);        //注意:所有子集都要添加,没有终止条件限制      for (int i = start; i < nums.size(); i++) {vec.push_back(nums[i]);backtrack(nums, i + 1);vec.pop_back();}    }vector<vector<int>> subsets(vector<int>& nums) {backtrack(nums, 0);return ans;}
};

题目三:90.子集II

题目链接

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

子集

(幂集)。

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

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
题解:回溯--子集问题

这个题算是上面那道的进化版吧,不过思路也差不多,只是数组里出现了重复元素,而要求结果中不能出现重复子集--这不就和昨天打卡不能出现重复组合一样了:对数组排序 + 跳过数组相邻相同的元素(横向同层处理使结果不出现重复子集)。

不理解的话,可以看看昨天的打卡内容,这里就不做分析了。

代码如下:

class Solution {
public:vector<vector<int>> ans;vector<int> vec;void backtrack(vector<int>& nums, int start) {ans.push_back(vec);for (int i = start; i < nums.size(); i++) {if (i > start && nums[i] == nums[i - 1]) {      //横向去重:用以跳过同一树层使用过的(重复)元素continue;       //注意这里是continue而不是break(break会直接跳出循环,这样一旦出现重复元素,会完全停止遍历剩余的元素,这会导致生成的子集不完整)}vec.push_back(nums[i]);backtrack(nums, i + 1);vec.pop_back();}}vector<vector<int>> subsetsWithDup(vector<int>& nums) {sort(nums.begin(), nums.end());         //先排序,这样重复的元素就会相邻backtrack(nums, 0);return ans;}
};

三、小结

今天的打卡就到此结束了,后边也会继续加油。最后,我是算法小白,但也希望终有所获。

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

相关文章:

  • python venv和virtualenv详解
  • 《征服数据结构》树堆(Treap)
  • 论文笔记:OneBit: Towards Extremely Low-bit Large Language Models
  • 英语文化中的音乐分类及其发展历史(Classical、Jazz、Rock、Pop、Electronic、Country、RB、Hip-Hop)
  • C语言-栈、队列、二叉树
  • pinia-plugin-persistedstate 插件不生效
  • sqlite 合并两个数据库中的特定表
  • winform中设置DateTimePicker参数为空
  • Python爬虫(8)
  • 靓图!多点创新!CEEMDAN-Kmeans-VMD-CNN-LSTM-Attention双重分解+卷积长短期+注意力多元时间序列预测
  • zdpgo_gin_limit 为zdpgo_gin打造的接口限流框架,当API接口需要限制访问频率的时候可以使用此框架
  • Java1234的Vue学习笔记
  • 嵌入式八股-C++面试91题(20240809)
  • 如何恢复误删视频?找回误删视频文件的办法分享
  • 游戏手柄开发一款游戏
  • 【阿旭机器学习实战】【39】脑肿瘤数据分析与预测案例:数据分析、预处理、模型训练预测、评估
  • 深度学习基础 - 梯度垂直于等高线的切线
  • py2exe打包
  • Gerrit存在两个未审核提交且这两个提交有冲突时的解决方案
  • 基于单片机的智能风扇设计
  • 【实战】Spring Security Oauth2自定义授权模式接入手机验证
  • Redis数据失效监听
  • 【达梦数据库】-SQL调优思路
  • DispatcherServlet 源码分析
  • 代码随想录算法训练营第十八天| 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先
  • 会议室占用的时间(75%用例)D卷(JavaPythonC++Node.jsC语言)
  • C++初阶_1:namespace
  • 低代码开发平台:效率革命还是质量隐忧?
  • 在 Django 表单中传递自定义表单值到视图
  • Android之复制文本(TextView)剪贴板