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

算法训练营day24 回溯算法③ 93.复原IP地址 、78.子集、 90.子集II

        今天继续回溯算法的专题,第三篇博客!

93.复原IP地址

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

        切割字符串为4段,当进行到第四段的时候对第四段字符串进行判断,是否可以输出到result数组中,优化:通过检查剩余位数来进行剪枝

回溯过程

  • 递归参数

        startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。本题我们还需要一个变量pointNum,记录添加逗点的数量。(记录已经是多少段了)

  • 递归终止条件

        本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。然后验证一下第四段是否合法,如果合法就加入到结果集里

  • 单层搜索的逻辑

        在for (int i = startIndex; i < s.size(); i++)循环中 [startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。

  • 如果合法就在字符串后面加上符号.表示已经分割。
  • 如果不合法就结束本层循环,如图中剪掉的分支:

        然后就是递归和回溯的过程:递归调用时,下一层递归的startIndex要从i+1开始,同时记录分割符的数量pointNum 要 +1。回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要-1。

判断子串是否合法

主要考虑到如下三点:

  • 段位以0为开头的数字不合法
  • 段位里有非正整数字符不合法
  • 段位如果大于255了不合法

回溯模版

void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}

代码实现

class Solution:def restoreIpAddresses(self, s: str) -> List[str]:result = []self.backtracking(s, 0, 0, '', result)return resultdef backtracking(self, s, start_index, point_num, current, result):# start_index: 标注下一层的循环开始位置# point_num: 切割逗点数量# current: 单个字符串保存# result: 结果数组集合存储if point_num == 3: #分割结束if self.is_valid(s, start_index, len(s) - 1):# 符合左闭右闭, 数组索引方式current += s[start_index: ]# 添加最后一段字符串result.append(current)return for i in range(start_index, len(s)):# range函数左闭右开# 判断该段字符是否符合, 如果不符合停止该层递归if self.is_valid(s, start_index, i): # 理解i的作用片段, 符合要求sub = s[start_index:i+ 1] # 切片左闭右开self.backtracking(s, i + 1, point_num + 1, current + sub + '.', result)# 理解python中的引用复制和复制赋值!else:breakdef is_valid(self, s, start, end):# 左闭右闭if start > end:return Falseif s[start] == '0' and start != end:# 开头数字为0return Falsenum = 0for i in range(start, end + 1):if not s[i].isdigit():return False # 判断是否遇到非数字字符num = num * 10 + int(s[i])if num > 255:return Falsereturn True

版本2(了解即可)

class Solution:def restoreIpAddresses(self, s: str) -> List[str]:results = []self.backtracking(s, 0, [], results)return resultsdef backtracking(self, s, index, path, results):if index == len(s) and len(path) == 4:results.append('.'.join(path))returnif len(path) > 4:  # 剪枝returnfor i in range(index, min(index + 3, len(s))):if self.is_valid(s, index, i):sub = s[index:i+1]path.append(sub)self.backtracking(s, i+1, path, results)path.pop()def is_valid(self, s, start, end):if start > end:return Falseif s[start] == '0' and start != end:  # 0开头的数字不合法return Falsenum = int(s[start:end+1])return 0 <= num <= 255

78.子集

        简单题目,属于组合范畴(普通模版级别),大家可以自己画一画树状图

回溯过程

  • 递归函数参数

        全局变量数组path为子集收集元素,二维数组result存放子集组合。(也可以放到递归函数参数里)递归函数参数在上面讲到了,需要startIndex。

  • 递归终止条件

        所剩集合为空的时候,就是叶子节点。那么什么时候剩余集合为空呢?就是startIndex已经大于数组的长度了,就终止了,因为没有元素可取了

  • 单层搜索逻辑

        求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树

class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:result = []path = []self.backtracking(nums, 0, path, result)return resultdef backtracking(self, nums, startIndex, path, result):result.append(path[:])for i in range(startIndex, len(nums)):path.append(nums[i])self.backtracking(nums, i + 1, path, result)path.pop()

90.子集II

        整数数组 nums ,其中可能包含重复元素,这个是困难的,所以要去重

        之前我们也做过一道去重的题目,更具体的说,这个就是“树枝去重”和“树层去重”的区别,毫无疑问,我们这道题仍然是树层去重,即树枝上存在相同元素是允许的,而书层上出现相同元素是不被允许的

        整体思路如下:是和之前“去重”思路完全一样的题目

代码实现(增加去重)

class Solution:def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:result = []path = []nums.sort()# 注意排序,这样相同的数字才可以放在一起,方便后续处理self.backtracking(nums, 0, path, result)return resultdef backtracking(self, nums, startIndex, path, result):result.append(path[:])for i in range(startIndex, len(nums)):if i > startIndex and nums[i] == nums[i - 1]: # 第一个遇到不要处理continuepath.append(nums[i])self.backtracking(nums, i + 1, path, result)path.pop()

代码实现(利用used数组)

class Solution:def subsetsWithDup(self, nums):result = []path = []used = [False] * len(nums)nums.sort()  # 去重需要排序self.backtracking(nums, 0, used, path, result)return resultdef backtracking(self, nums, startIndex, used, path, result):result.append(path[:])  # 收集子集for i in range(startIndex, len(nums)):# used[i - 1] == True,说明同一树枝 nums[i - 1] 使用过# used[i - 1] == False,说明同一树层 nums[i - 1] 使用过# 而我们要对同一树层使用过的元素进行跳过if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:continuepath.append(nums[i])used[i] = Trueself.backtracking(nums, i + 1, used, path, result)used[i] = Falsepath.pop()

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

相关文章:

  • 零基础入门:用C++从零实现TCP Socket网络小工具
  • 人脸检测算法——SCRFD
  • Ubuntu系统下快速体验iperf3工具(网络性能测试)
  • 2G和3G网络关闭/退网状态(截止2025年7月)
  • Python技术题1
  • 【RK3576】【Android14】开发环境搭建
  • 基于现代R语言【Tidyverse、Tidymodel】的机器学习方法与案例分析
  • 用 React-Three-Fiber 实现雪花下落与堆积效果:从零开始的 3D 雪景模拟
  • 前端迟迟收不到响应,登录拦截器踩坑!
  • 小结:Spring MVC 的 XML 的经典配置方式
  • ASP.NET Core Web API 内存缓存(IMemoryCache)入门指南
  • untiy之导入插件(文件方式,适用于git克隆失败)
  • Instagram千号矩阵:亚矩阵云手机破解设备指纹检测的终极方案
  • 【.net core】支持通过属性名称索引的泛型包装类
  • 五国联动!德法意西荷 ASIN 同步上架成泛欧计划硬性门槛
  • 构建智能客服Agent:从需求分析到生产部署
  • 持续同调文章阅读(四)
  • 推荐 1 款 4.5k stars 的AI 大模型驱动的开源知识库搭建系统
  • A33-vstar笔记及资料分享:搭建交叉编译环境
  • Linux云计算基础篇(9)-文本处理工具和变量
  • 无符号乘法运算的硬件逻辑实现 ————取自《湖科大教书匠》
  • 【PTA数据结构 | C语言版】多叉堆的上下调整
  • Python MP3 归一化器和长度分割器实用工具开发指南
  • SQL映射文件
  • Android 应用保活思路
  • 树(Tree)
  • 【C++基础】--多态
  • web域名解析
  • 信息论至AI实践:交叉熵的原理全景与应用深度解析
  • Github库镜像到本地私有Gitlab服务器