代码随想录算法训练营第二十七天 | 93.复原IP地址,78.子集,90.子集II

news2024/9/27 21:30:37

一、参考资料

复原IP地址

题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html

视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/

子集

题目链接/文章讲解:https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html

视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci

子集II

题目链接/文章讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html

视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J

二、LeetCode93.复原IP地址

https://leetcode.cn/problems/restore-ip-addresses/description/

有效 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 仅由数字组成

切割问题可以抽象为树型结构,如图:

感觉在昨天的基础上理解~思路顺畅好多

class Solution {
private:
    vector<string> res;
    bool isValid(string s, int begin, int end) {
        if (begin > end) return false;
        if (s[begin] == '0' && begin != end) return false;
        int num = 0;
        for (int i = begin; i <= end; i++) {
            if (s[i] < '0' || s[i] > '9') return false;
            num = num * 10 + (s[i] - '0');
            if (num > 255) return false;
        }
        return true;
    }
    void backtracking(string& s, int startIndex, int pointNum) {
        if (pointNum == 3) {
            if (isValid(s, startIndex, s.size() - 1)) {
                res.push_back(s);
            }
            return ;
        }
        for (int i = startIndex; i < s.size(); i++) {
            if (isValid(s, startIndex, i)) {
                s.insert(s.begin() + i + 1, '.');
                pointNum += 1;
                backtracking(s, i + 2, pointNum);
                pointNum -= 1;
                s.erase(s.begin() + i + 1);
            } else break;
        }
    }
public:
    vector<string> restoreIpAddresses(string s) {
        if (s.size() < 4 || s.size() > 12) return res;
        backtracking(s, 0, 0);
        return res;
    }
};

带注释版:

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+2
                pointNum--;                         // 回溯
                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;
    }
};

三、LeetCode78.子集

https://leetcode.cn/problems/subsets/description/

给你一个整数数组 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 {
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;
    }
};

在注释中,可以发现可以不写终止条件,因为本来我们就要遍历整棵树。

有的同学可能担心不写终止条件会不会无限递归?

并不会,因为每次递归的下一层就是从i+1开始的。

我写的如下~【唔,理解了思路后first blood】

class Solution {
private:
    vector<int> path;
    vector<vector<int>> res;

    void backtracking (vector<int> nums, int startIndex) {
        res.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) {
        backtracking(nums, 0);
        return res;
    }
};

四、LeetCode90.子集II

https://leetcode.cn/problems/subsets-ii/description/

给你一个整数数组 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 {
private:
    vector<vector<string>> result;
    vector<string> path; // 放已经回文的子串
    void backtracking (const string& s, int startIndex) {
        // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
        if (startIndex >= s.size()) {
            result.push_back(path);
            return;
        }
        for (int i = startIndex; i < s.size(); i++) {
            if (isPalindrome(s, startIndex, i)) {   // 是回文子串
                // 获取[startIndex,i]在s中的子串
                string str = s.substr(startIndex, i - startIndex + 1);
                path.push_back(str);
            } else {                                // 不是回文,跳过
                continue;
            }
            backtracking(s, i + 1); // 寻找i+1为起始位置的子串
            path.pop_back(); // 回溯过程,弹出本次已经填在的子串
        }
    }
    bool isPalindrome(const string& s, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            if (s[i] != s[j]) {
                return false;
            }
        }
        return true;
    }
public:
    vector<vector<string>> partition(string s) {
        result.clear();
        path.clear();
        backtracking(s, 0);
        return result;
    }
};

优化后的代码就没详细学了

我能自己写出这个题的代码,已经觉得自己真的进步很大了:

class Solution {
private:
    vector<string> path;
    vector<vector<string>> res;

    bool isPalinedromic(string s, int begin, int end) {
        for (int i = begin, j = end; i < j; i++, j--) {
            if (s[i] != s[j]) return false;
        }
        return true;
    }

    void backtracking (string s, int startIndex) {
        if(startIndex > s.size()) return ;
        if (startIndex == s.size()) {
            res.push_back(path);
            return ;
        }
        for(int i = startIndex; i < s.size(); i++) {
            if(isPalinedromic(s, startIndex, i)) {
                string str = s.substr(startIndex, i - startIndex + 1);
                path.push_back(str);
            } else continue;
            backtracking(s, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<string>> partition(string s) {
        backtracking(s, 0);
        return res;
    }
};

今日总结:

题目确实是当天写完的,只是博客没有及时写

  1. 感觉到自己真的进步好多了,能够理解懂视频的题目讲解,经历一些debug后还能尝试控制时间的前提下独立完成代码。

  1. 今天的难点应该挺多的,我花了很多时间理解来着,讲解回文串分割的视频应该看了两遍。

  1. 另外今天的组合数一个不太容易想到题解的“去重”问题,也是挺困扰,希望真的掌握后能做到举一反三呢

继续加油哈小赵~

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

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

相关文章

乐观锁、雪花算法、MyBatis-Plus多数据源

乐观锁、雪花算法、MyBatis-Plus多数据源e>雪花算法2、乐观锁a>场景b>乐观锁与悲观锁c>模拟修改冲突d>乐观锁实现流程e>Mybatis-Plus实现乐观锁七、通用枚举a>数据库表添加字段sexb>创建通用枚举类型c>配置扫描通用枚举d>测试九、多数据源1、创建…

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(二级)答案解析

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;二级&#xff09; 一、单选题(共25题&#xff0c;共50分) 1. 一个骰子&#xff0c;从3个不同角度看过去的点数如图所示&#xff0c;请问5的对面是什么点数&#xff1f;&#xff08; &#xff09; …

数据库(单表查询)

素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 varchar(10) NOT NUL…

【C语言技能树】程序环境和预处理

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

一文掌握,单机Redis、哨兵和Redis Cluster的搭建,建议收藏

本篇文章讲述了 Redis 单机环境、主备、哨兵 Sentinel 模式以及 Redis Cluster 集群模式下的操作步骤&#xff0c;关于这些操作我们没必要死记硬背&#xff0c;只需要总结下来&#xff0c;下次使用直接拿出来就好。建议当作操作手册收藏。安装单实例 Redis编译Redis1.下载Redis…

小白都能学会的红帽(RedHat8)RHEL8系统安装实战

文章目录前言一. 实验环境二. 安装虚拟机三. 安装操作系统四. 系统安装成功后的操作总结前言 本文是应一位大佬的提议&#xff0c;建议我写写红帽系列&#xff0c;centos8已经不维护了&#xff0c;centos7 维护到2024年6月30日&#xff0c; 也就是明年的事情了&#xff0c;所以…

【Flutter入门到进阶】Dart基础篇---基于对比Java学习Dart

1 Dart语言特性 1.1 简介 1.1.1 说明 2011年10月&#xff0c;在丹麦召开的 GOTO 大会上&#xff0c;Google 发布了一种新的编程语言 Dart 。如同 Kotlin 和 Swift 的出现&#xff0c;分别是为了解决 Java 和 Objective-C 在编写应用程序的一些实际问题一样&#xff0c;Dart 的…

算法笔记(二)—— 认识N(logN)的排序算法

递归行为的时间复杂度估算 整个递归过程是一棵多叉树&#xff0c;递归过程相当于利用栈做了一次后序遍历。 对于master公式&#xff0c;T(N)表明母问题的规模为N&#xff0c;T(N/b)表明每次子问题的规模&#xff0c;a为调用次数&#xff0c;加号后面表明&#xff0c;除去调用之…

八股初始:RocketMQ

一、消息队列介绍 消息队列是什么 对于 MQ 来说&#xff0c;其实不管是 RocketMQ、Kafka 还是其他消息队列&#xff0c;它们的本质都是&#xff1a;一发一存一消费。 将 MQ 掰开了揉碎了来看&#xff0c;都是「一发一存一消费」&#xff0c;再直白点就是一个「转发器」。生产…

记一次上环境获取资源失败的案例

代码结构以及资源位置 测试代码 RestController RequestMapping("/json") public class JsonController {GetMapping("/user/1")public String queryUserInfo() throws Exception {// 如果使用全路径, 必须使用/开头String path JsonController.class.ge…

《计算机组成与设计》03. 计算机的算术运算

文章目录整数运算加法与减法乘法普通十进制乘法硬件中实现步骤例子乘法器的设计除法普通十进制除法硬件中实现步骤例子除法器的设计浮点数运算科学计数法、规格化数浮点表示单精度浮点数双精度浮点数移码表示法IEEE 754指数偏移值&#xff08;exponent bias&#xff09;规格化的…

计算机网络4:计算机网络体系结构

目录计算机网络体系结构1.网络模型2.每一层的代表含义2.1 OSI7层模型2.2 五层协议2.3 TCP/IP 四层协议3.数据在各层之间的传输过程4.为什么要进行分层计算机网络体系结构 1.网络模型 2.每一层的代表含义 2.1 OSI7层模型 &#xff08;1&#xff09;物理层&#xff1a;比特流–…

STC15中断系统介绍

STC15中断系统介绍✨本篇参考来源于STC官方stc15系列手册:538页- 589页。&#xff08;文末提供该摘取部分的文档资料&#xff09; &#x1f389;在官方提供的手册资料中&#xff0c;一个系列一份手册&#xff0c;手册内容涵盖了数据手册和参考手册以及例程案例。对于学习着来说…

彻底搞懂分布式系统服务注册与发现原理

目录 引入服务注册与发现组件的原因 单体架构 应用与数据分离

火遍全球的ChatGPT技术简介与主干网络代码

如果说当下最火的AI技术和话题是什么&#xff0c;恐怕很难绕开ChatGPT。各大厂商都在表示未来要跟进ChatGPT技术&#xff0c;开发在自然语言处理智能系统&#xff0c;可见其影响力。本篇博客追个热度&#xff0c;来简单的介绍下ChatGPT到底是一项什么技术&#xff0c;究竟如何完…

深入理解innodb存储格式,双写机制,buffer pool底层结构和淘汰策略

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…

【网络编程】Java中的Socket

文章目录前言socket是什么&#xff1f;Java中的SocketJava实现网络上传文件前言 所谓Socket&#xff08;套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用…

kafka入门篇

文章目录前言介绍概念与说明安装启动配置命令操作创建topic查看topic列表发送消息&#xff08;启动一个生产者&#xff09;消费消息&#xff08;启动一个消费者&#xff09;查询topic信息删除topic集群关机使用报错java连接示例前言 作为入门篇&#xff0c;主要是了解Kafka的概…

在windows下载安装netcat(nc)命令

参考文章 一、netcat(nc)下载 网盘下载 netcat(nc)下载地址&#xff1a;netcat 1.11 for Win32/Win64 二、配置环境变量 在Path里添加netcat的存放路径 参数 说明 -C 类似-L选项&#xff0c;一直不断连接[1.13版本新加的功能] -d 后台执行 -e prog 程序重定向&am…

能取代90%人工作的ChatGPT到底牛在哪?

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; &#x1f38d;大家好&#xff0c;我是慕枫 &#x1f38d;前阿里巴巴高级工程师&#xff0c;InfoQ签约作者、阿里云专家博主&#xff0c;一直致力于用大白话讲解技术知识 &#x…