代码随想录训练营 Day24打卡 回溯算法part03 93. 复原IP地址 78. 子集 90. 子集II

news2024/9/21 16:41:32

代码随想录训练营 Day24打卡 回溯算法part03

一、 力扣93. 复原IP地址

有效 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 中的任何数字。你可以按 任何 顺序返回答案。
示例
输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]

切割问题可以抽象为树型结构,如图:
在这里插入图片描述
实现思路

  1. 初始调用:

    调用 restoreIpAddresses 方法时,初始化结果列表并调用 backtracking 方法。

  2. 回溯函数 backtracking:

    当逗点数量为 3 时,判断最后一段子字符串是否合法,如果合法则添加到结果列表中。
    循环遍历字符串,判断当前子字符串是否合法,若合法则递归调用回溯函数。
    不合法时,停止当前循环。

  3. 验证函数 is_valid:

    判断子字符串是否符合 IP 地址段的规则:不能有前导零、不能大于 255、必须是数字字符。

版本一 回溯法

from typing import List

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        result = []
        # 初始调用回溯函数,开始索引、逗点数量、当前字符串、结果列表
        self.backtracking(s, 0, 0, "", result)
        return result

    def backtracking(self, s, start_index, point_num, current, result):
        if point_num == 3:  # 逗点数量为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)):
            if self.is_valid(s, start_index, i):  # 判断 [start_index, i] 这个区间的子串是否合法
                sub = s[start_index:i + 1]  # 获取当前段
                # 递归调用回溯函数,传入新的开始索引、增加的逗点数量、当前字符串、结果列表
                self.backtracking(s, i + 1, point_num + 1, current + sub + '.', result)
            else:
                break  # 不合法则停止循环

    def is_valid(self, s, start, end):
        if start > end:
            return False
        if s[start] == '0' and start != end:  # 0开头的数字不合法
            return False
        num = 0
        for i in range(start, end + 1):
            if not s[i].isdigit():  # 遇到非数字字符不合法
                return False
            num = num * 10 + int(s[i])  # 累积数字
            if num > 255:  # 如果大于255了不合法
                return False
        return True

版本二 回溯法

实现思路

  1. 初始调用:

    调用 restoreIpAddresses 方法时,初始化结果列表并调用 backtracking 方法。

  2. 回溯函数 backtracking:

    当遍历完字符串且路径长度为 4 时,将路径加入结果列表。
    路径长度大于 4 时,停止回溯(剪枝)。
    循环遍历字符串,判断当前子字符串是否合法,若合法则递归调用回溯函数并回溯路径。

  3. 验证函数 is_valid:

    判断子字符串是否符合 IP 地址段的规则:不能有前导零、必须在 0 到 255 之间。

from typing import List

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        results = []
        # 初始调用回溯函数,开始索引、路径、结果列表
        self.backtracking(s, 0, [], results)
        return results

    def backtracking(self, s, index, path, results):
        if index == len(s) and len(path) == 4:  # 完全遍历字符串且路径长度为4(四段IP)
            results.append('.'.join(path))  # 加入结果列表
            return

        if len(path) > 4:  # 剪枝:路径长度大于4时停止
            return

        for i in range(index, min(index + 3, len(s))):  # 每段最长3个字符
            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 False
        if s[start] == '0' and start != end:  # 0开头的数字不合法
            return False
        num = int(s[start:end+1])  # 将子字符串转为整数
        return 0 <= num <= 255  # 数字必须在0到255之间

力扣题目链接
题目文章讲解
题目视频讲解

二、 力扣78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:

在这里插入图片描述
从图中红线部分,可以看出遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合。

实现思路

  1. 初始调用:

    调用 restoreIpAddresses 方法时,初始化结果列表并调用 backtracking 方法。

  2. 回溯函数 backtracking:

    当遍历完字符串且路径长度为 4 时,将路径加入结果列表。
    路径长度大于 4 时,停止回溯(剪枝)。
    循环遍历字符串,判断当前子字符串是否合法,若合法则递归调用回溯函数并回溯路径。

  3. 验证函数 is_valid:

    判断子字符串是否符合 IP 地址段的规则:不能有前导零、必须在 0 到 255 之间。

代码实现

from typing import List

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        results = []
        # 初始调用回溯函数,开始索引、路径、结果列表
        self.backtracking(s, 0, [], results)
        return results

    def backtracking(self, s, index, path, results):
        if index == len(s) and len(path) == 4:  # 完全遍历字符串且路径长度为4(四段IP)
            results.append('.'.join(path))  # 加入结果列表
            return

        if len(path) > 4:  # 剪枝:路径长度大于4时停止
            return

        for i in range(index, min(index + 3, len(s))):  # 每段最长3个字符
            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 False
        if s[start] == '0' and start != end:  # 0开头的数字不合法
            return False
        num = int(s[start:end+1])  # 将子字符串转为整数
        return 0 <= num <= 255  # 数字必须在0到255之间

力扣题目链接
题目文章讲解
题目视频讲解

三、 力扣90. 子集II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

做本题之前一定要先做78.子集 。

这道题目和78.子集区别就是集合里有重复元素了,而且求取的子集要去重。

那么关于回溯算法中的去重问题,在40.组合总和II (opens new window)中已经详细讲解过了,和本题是一个套路。

用示例中的[1, 2, 2] 来举例,如图所示: (注意去重需要先对集合排序)

在这里插入图片描述

从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!

实现思路

  1. 初始化:

    result:用于存储所有子集的结果列表。
    path:用于存储当前探索的路径(子集)。
    used:用于标记数组中的元素是否被使用过,以避免重复。
    将数组 nums 进行排序,方便后续去重操作。
    调用 backtracking 方法,开始回溯算法。

  2. 回溯函数 backtracking:

    每次进入递归函数,都将当前路径 path 添加到结果列表 result 中,表示一个子集。
    循环遍历数组 nums,从 startIndex 开始,以避免重复子集。
    检查当前元素是否与前一个元素相同,且前一个元素未被使用过,以避免在同一树层上出现重复的元素组合。
    对于每个元素:
        将当前元素添加到路径 path 中。
        标记当前元素为已使用 used[i] = True。
        递归调用 backtracking,探索以当前元素为起点的所有子集。
        回溯操作,取消当前元素的使用标记 used[i] = False,并从路径中移除最后一个元素 path.pop()。

代码实现

class Solution:
    def subsetsWithDup(self, nums):
        result = []  # 用于存放所有子集的结果列表
        path = []    # 当前探索的路径(子集)
        used = [False] * len(nums)  # 用于标记元素是否被使用过
        nums.sort()  # 去重需要排序
        self.backtracking(nums, 0, used, path, result)  # 调用回溯函数
        return result  # 返回最终的结果列表

    def 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]:
                continue
            
            path.append(nums[i])  # 将当前元素添加到路径中
            used[i] = True  # 标记当前元素为使用过
            # 递归调用,探索以当前元素为起点的所有子集
            self.backtracking(nums, i + 1, used, path, result)
            used[i] = False  # 回溯,取消当前元素的使用标记
            path.pop()  # 回溯,移除路径中的最后一个元素

# 示例
sol = Solution()
print(sol.subsetsWithDup([1, 2, 2]))

力扣题目链接
题目文章讲解
题目视频讲解

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

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

相关文章

扩展【从0制作自己的ros导航小车】C++_ROS_QT5联合编译,简单界面为ROS开发增添交互

从0制作自己的ros导航小车 前言一、环境搭建二、联合编译三、测试 前言 前面已经实现了导航功能&#xff0c;对于之后的一些开发&#xff0c;有交互能力是比较重要的&#xff0c;比如小车上连接一块屏幕&#xff0c;通过屏幕来选择模式&#xff0c;可视化等等。QT是不错的选择…

2024年云计算企业CRM应用与选型研究报告

数字化时代&#xff0c;所有行业都在经历着数字化转型带来的效率革命。在业务流程、协同办公、数据收集和利用、决策方式等诸多方面&#xff0c;在数字化转型的加持下&#xff0c;各行各业的企业都会经历从低效到高效、从无序杂乱到标准化流程和数据驱动决策的成长蜕变。 在IC…

LeetCode 100道题目和答案(一)

1.两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按…

【安卓】SQLite数据库存储-创建数据库与增删改查

文章目录 创建数据库更新数据库增加数据修改数据删除数据查询数据 安卓专门提供了一个SQLiteOpenHelper帮助类&#xff0c;借助这个类可以非常简单地对数据库进行创建和升级。SQLiteOpenHelper是一个抽象类&#xff0c;使用它需要创建一个自己的帮助类去继承它。SQLiteOpenHelp…

巴黎同款,六自由度技术还原赛场决定性瞬间!

现代纪实摄影大师亨利布列松&#xff0c;曾提出了“决定性瞬间”&#xff08;The Decisive Moment&#xff09;理论——拍摄者捕捉到的画面越稍纵即逝&#xff0c;越难以复制&#xff0c;越宝贵。 很多摄影师的经典作品&#xff0c;都来自那决定性的千分之一秒。 ● 布列松摄于…

OpenCV 读取 MP4 视频

在 C 中结合 OpenCV 库来读取 MP4 视频文件是一个常见的任务。以下是一个简单的示例程序&#xff0c;说明了如何使用 OpenCV 的 VideoCapture 类来打开一个 MP4 文件并逐帧显示每一帧。 VideoCapture::VideoCapture(const string& filename)&#xff1b;参数&#xff1a;f…

一个Android下载网络图片显示并保存到系统相册的完整案例

文章目录 1. 案例简介1.1 效果演示 2. 工程配置3. 网络层3.1 网络接口定义3.2 Retrofit工具类 4. 主界面及完整代码4.1 完整主界面代码 ImageDownloadActivity4.2 布局文件 5. 总结 1. 案例简介 在 Android开发 中&#xff0c;下载图片保存到本地是常见的需求&#xff0c;看似…

一个简单的录音软件(利用QT录音,ffmpeg进行音频重采样,fdk-aac编码)

录音软件是一种非常有用的工具&#xff0c;可以帮助我们记录和存储语音信息。在本文中&#xff0c;我们将介绍一个简单的录音软件&#xff0c;该软件利用QT进行录音&#xff0c;使用ffmpeg进行音频重采样&#xff0c;并使用fdk-aac编码。 一、 环境介绍 1、QT版本: QT5.…

绕过微信电脑版旧版本限制,版本过低不给登录的问题

这张图&#xff0c;对于还在使用低版本微信电脑版的人很熟悉了吧&#xff01;因为微信逐步开始限制低版本的客户端了&#xff0c;导致无法登陆进去。 为什么这么多人还在使用旧版&#xff1f; 因为很多机器人、框架、HOOK版本的微信等等都是在旧版的基础上开发的&#xff0c;…

嘉立创PCB板子降层(从4层到2层实例)

降层导致的改变 走线和连接&#xff0c;若想正常设计先把要用的内容全部移动到其他层。若不使用可以按照下面方式全部删除。 删除定义使用的规则 删除在需要删除层的走线等所有内容

相同的 LLM 在「不同 GPU 上」会产生不同输出?为什么?

编者按&#xff1a; 在大语言模型(LLMs)的部署及其相关的算力扩容过程中&#xff0c;更换 GPU 是否也可能会对模型的输出产生重大影响&#xff1f;这个问题的答案对于确保 LLMs 在不同硬件环境下的一致性和可靠性至关重要。 我们今天为大家带来的这篇文章&#xff0c;作者的核心…

利用docker部署图形化工具 portainer

docker查找图形化工具 Portainer 拉取镜像 docker pull portainer/portainer启动docker UI容器 docker run -d -p 9209:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v /opt/data3/mydocker/portainer_data:/data portainer/porta…

MFC多个控件组合存在显示不出来现象

MFC多个控件组合存在显示不出来现象 1、找到rc文件 &#xff0c; 右键查看代码 2、 3、将基础组件放在最前面即可

C++(week16): C++提高:(六) Qt基础

文章目录 零、课前须知一、Qt基础1.CLI与GUI2.事件驱动模型3.Qt快捷键 二、QtCreator1.Qt的安装&#xff1a;Qt框架、IDE2.Qt的六大模式3.核心模块4.布局5.Qt项目中的文件6.信号与槽机制7.添加资源&#xff1a;资源文件qrc8.main.cpp解析(1)ui文件 和 纯代码(2)按钮 信号槽机制…

在嵌入式Linux平台上使用Nginx搭建RTMP流媒体服务器

概述 Nginx是一个以高效稳定著称的高性能的HTTP和反向代理web服务器&#xff0c;它同时也是基于事件驱动开发的异步高性能跨平台服务器。Nginx-RTMP是基于Nginx框架的模块开发&#xff0c;很好地继承了Nginx的异步高性能以及扩展性好的优点。 RTMP 是 Real Time Messaging Pr…

docker 部署 ElasticSearch;Kibana

ELasticSearch 创建网络 docker network create es-netES配合Kibana使用时需要组网&#xff0c;使两者运行在同一个网络下 命令 docker run -d \ --name es \ -e "discovery.typesingle-node" \ -v /usr/local/es/data:/usr/share/elasticsearch/data \ -v /usr/…

C语言——编译与链接

目录 引言 翻译环境与运行环境 翻译环境 1.翻译环境的简述 2.编译过程 2.1 预处理&#xff08;预编译&#xff09; 2.2 编译 2.2.1 词法分析 2.2.2 语法分析 2.2.3 语义分析 2.3 汇编 3.链接 运行环境 结束语 引言 C语言编译与链接过程是理解程序如何从代码转化…

8月5日学习笔记 glibc安装与安全用户角色权限

一&#xff0c;glibc安装 https://www.mysql.com/ 官⽹ https://downloads.mysql.com/archives/community/ https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.33-li nux-glibc2.12-x86_64.tar 安装步骤 1.安装依赖库 [rootlocalhost ~]# yum list installed |g…

在vscode中使用ssh运行docker:从下载到运行全流程

首先在本机或者服务器上下载docker并运行 本文目的旨在本机下载docker并打包&#xff0c;然后在服务器上进行加载 docker -v Docker version 27.0.3, build 7d4bcd8有输出说明在运行 一、下载 在docker hub上下载docker以tensorflow为例 点击tag搜索自己想要的版本 copy命…

All-Reduce通信原语;Reduce+LayerNorm+Broadcast算子;gRPC:远程过程调用(RPC)框架;

目录 All-Reduce通信原语 定义与作用 实例说明 示例图解(以Ring算法为例) 结论 Reduce+LayerNorm+Broadcast算子 1. Reduce算子 2. LayerNorm算子 3. Broadcast算子 组合使用场景 gRPC:远程过程调用(RPC)框架 All-Reduce通信原语 是计算机科学中,特别是在分布式…