代码随想录算法训练营第二十八天 | 三个逗点四个子串的类型题、子集题要取所有节点、子集与树层去重

news2024/9/28 13:23:27

93.复原IP地址

文档讲解:代码随想录 (programmercarl.com)

视频讲解:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址_哔哩哔哩_bilibili

状态:不会做。这是三个逗点四个子串的类型题

思路

这是切割问题,切割问题就可以使用回溯搜索法把所有可能性搜出来。切割问题可以抽象为树型结构,如图:

在这里插入图片描述

回溯三部曲

  1. 递归参数

    切割问题类似组合问题,startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。

    本题我们还需要一个变量pointNum,记录添加逗点的数量

    本题没有用path记录每一个结果,而是递归时直接在string s中的切割处加入".“,达到递归终止条件时,直接将string加入result;回溯时,从string s中去掉“.”。

    vector<string> result;// 记录结果
    // startIndex: 搜索的起始位置,pointNum:添加逗点的数量
    void backtracking(string& s, int startIndex, int pointNum) {
    
  2. 递归终止条件

    终止条件和131.分割回文串 (opens new window)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。

    pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。

    然后验证一下第四段是否合法,如果合法就加入到结果集里

    if (pointNum == 3) { // 逗点数量为3时,分隔结束
        // 判断第四段子字符串是否合法,如果合法就放进result中
        if (isValid(s, startIndex, s.size() - 1)) {
            result.push_back(s);
        }
        return;
    }
    
  3. 单层搜索的逻辑

    在131.分割回文串 (opens new window)中已经讲过在循环遍历中如何截取子串。

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

    如果合法就在字符串后面加上符号.表示已经分割。

    如果不合法就结束本层循环,如图中剪掉的分支:注意这里是break结束本层循环,而131.分割回文串 (opens new window)是continue跳过本轮循环,这是因为当前子串若不合法,即使加上一个新字符也不会合法;而131题中,若当前子串不回文,加上一个新字符是有可能回文的

在这里插入图片描述

然后就是递归和回溯的过程:

递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入分隔符.,同时记录分割符的数量pointNum 要+1。

回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要-1。

//!!i在每层里递增,startIndex在递归到下一层时改变
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; // 不合法,直接结束本层循环
}

判断是否合法

主要考虑到如下三点:

  • 段位以0为开头的数字不合法
  • 段位里有非正整数字符不合法
  • 段位如果大于255了不合法
// 判断字符串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;
}

整体代码

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;
    }
};

78.子集

文档讲解:代码随想录 (programmercarl.com)

视频讲解:回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集_哔哩哔哩_bilibili

状态:刚开始没写出来,看了树形图写出来了。重点要学会画树形图。

思路

①如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

②其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!

③什么时候for可以从0开始呢?求排列问题的时候,就要从0开始,因为集合是有序的,{1, 2} 和{2, 1}是两个集合。

以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:从图中红线部分,可以看出遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合

在这里插入图片描述

回溯三部曲

  1. 递归函数参数

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

    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums, int startIndex) {
    
  2. 递归终止条件

    如上图,剩余集合为空的时候,就是叶子节点。

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

    if (startIndex == nums.size()) {
        return;
    }
    

    其实可以不需要加终止条件,因为startIndex >= nums.size(),本层for循环本来也结束了

  3. 单层搜索逻辑

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

    for(int i = startIndex; i < nums.size(); ++i){
        path.push_back(nums[i]);// 子集收集元素
        ++i;
        backtracking(nums, i);// 元素不重复取
        --i;
        path.pop_back();// 回溯
    }
    

整体代码

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int startIndex){
        result.push_back(path);	//每个树节点都是一个答案

        for(int i = startIndex; i < nums.size(); ++i){
            path.push_back(nums[i]);
            ++i;
            backtracking(nums, i);
            --i;
            path.pop_back();
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums, 0);
        return result;
    }
};

回溯小结

本周小结!(回溯算法系列二) | 代码随想录 (programmercarl.com)

90.子集II

文档讲解:代码随想录 (programmercarl.com)

视频讲解:回溯算法解决子集问题,如何去重?| LeetCode:90.子集II_哔哩哔哩_bilibili

状态:能做出来。上一题的方法加上树层去重(组合题40的方法)即可。

思路

按照上一题的方法画出树形图,如下所示,很明显可以看出:出现树层重复,因此只需要在上一题的基础上进行树层去重即可。

在这里插入图片描述

代码

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums, int startIndex, vector<bool>& used){
        result.push_back(path);

        for(int i = startIndex; i < nums.size(); ++i){
            if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;  //对同一树层重复的元素进行跳过

            path.push_back(nums[i]);
            used[i] = true;
            ++i;
            backtracking(nums, i, used);
            --i;
            used[i] = false;
            path.pop_back();
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<bool> used(nums.size(), false);  //全部初始化为false
        sort(nums.begin(), nums.end());
        backtracking(nums, 0, used);
        return result;
    }
};

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

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

相关文章

重新定义分析 - EventBridge 实时事件分析平台发布

对于日志分析大家可能并不陌生&#xff0c;在分布式计算、大数据处理和 Spark 等开源分析框架的支持下&#xff0c;每天可以对潜在的数百万日志进行分析。 事件分析则和日志分析是两个完全不同的领域&#xff0c;事件分析对实时性的要求更高&#xff0c;需要磨平事件领域中从半…

【STM32】基础知识 第十一课 时钟

【STM32】基础知识 第十一课 时钟 概述时钟系统的基本概念什么是时钟时钟树锁相环APB 时钟树F1 系列时钟树F4 系列时钟树F7 系列时钟树H7 系列时钟树 系统时钟配置系统时钟配置步骤外设时钟的使能和使能HAL_RCC_OscConfig() 函数HAL_RCC_ClockConfig() 函数 概述 STM32 微控制…

超级香,分享8个相见恨晚的Python库

看到新奇又实用的第三方库&#xff0c;当然要分享出来咯~ Plottable Plottable是一个Python库&#xff0c;用于在matplotlib基础上绘制精美表格。例如下图所示表格。 代码如下&#xff1a; import matplotlib.pyplot as plt import numpy as np import pandas as pd from ma…

Leangoo领歌轻量级协作-OKR目标管理

​本场景是OKR目标管理模板&#xff0c;用Leangoo管理和跟踪OKR可以提升OKR的透明度和传递的即时性&#xff0c;驱动团队的积极性、促进共享和协作、提升沟通和协作的效率&#xff0c;帮助企业快速落地OKR。 OKR&#xff08;Objectives and Key Results目标与关键结果&#xf…

Packet Tracer - 谁会听到广播?

Packet Tracer - 谁会听到广播&#xff1f; 目标 第 1 部分&#xff1a;观察 VLAN 实施中的广播流量 第 2 部分&#xff1a;完成思考题 拓扑图 场景 在本练习中&#xff0c;将完全填充一个配有 24 个端口的 Catalyst 2960 交换机。 所有端口都已使用。 您将观察 VLAN 实施…

PS磨皮插件portraiture最新版磨皮工具

Portraiture是一款智能磨皮插件&#xff0c;为Photoshop和Lightroom添加一键磨皮美化功能&#xff0c;快速对照片中皮肤、头发、眉毛等部位进行美化&#xff0c;无需手动调整&#xff0c;大大提高P图效率。全新4版本&#xff0c;升级AI算法&#xff0c;并独家支持多人及全身模式…

剪纸中秋海报

打开【Ps】&#xff0c;新建【A4画布】&#xff0c;双击背景图层【解锁】&#xff0c;再添加【图案叠加】图层样式&#xff0c;选择最后一个图案&#xff0c;增加【缩放】。 【椭圆选框工具】按住【Shift】键画一个正圆&#xff0c;填充颜色#0e8993&#xff0c;添加【渐变叠加】…

假期做了一项调研:大厂为何都要自研RPC框架?结果合乎情理

大家好&#xff0c;我是冰河~~ 五一假期过的可真快&#xff0c;今天开始&#xff0c;又要搬砖了。在五一假期当中&#xff0c;冰河做了一项调研&#xff0c;感觉结果还是挺合乎情理的。 翻看招聘信息 先来看我在某招聘网站上随便搜索了下Java招聘的岗位&#xff0c;看到的招…

做好防雷检测的重要意义和作用

防雷检测是一项非常重要的工作&#xff0c;它可以保障人们的生命财产安全&#xff0c;并维护国家的安全稳定。地凯科技将从防雷的重要性、防雷检测的行业应用和防雷行业国标三个方面来阐述防雷检测的重要性。 一、防雷的重要性 随着科技的不断发展&#xff0c;人们的生活和工作…

unity中实现经典的2d横版单向跳跃平台

经常玩2d横版游戏的朋友们相信对这样的效果一定对这种单向跳跃平台很熟悉&#xff1a;我希望我的角色可以通过跳跃跳上平台&#xff0c;然后在平台之上按下键盘的下键后从平台上落下。 那么想要实现这样的效果具体要怎么做呢&#xff1f;我们还是先将想要实现的效果进行一个逻…

微服务分布式搜索引擎 ElasticSearch 搜索结果处理 排序、分页与高亮

文章目录 ⛄引言一、排序⛅普通字段排序⚡地理坐标排序 二、分页⌚基本分页⏰深度分页 三、高亮⚡实现高亮 ⛵小结 ⛄引言 本文参考黑马 分布式Elastic search Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中…

python 实现模糊聚类

python模糊聚类细节与实现 前言数学逻辑代码框架Python实现数据预处理 preProcess获得相似矩阵 getSimilarityMatrix获取传递闭包 transitiveClosure模糊运算 fuzzMatrixProduct实现聚类 mergeProcess 实例演示 ![在这里插入图片描述](https://img-blog.csdnimg.cn/b062c59c282…

【Redis】持久化机制详解:从RDB到AOF,你需要知道的一切

本文目录 RDB&#xff08;默认&#xff09; 自动触发 &#x1f19a; 手动触发 优点 缺点 何时会触发RDB快照 AOF 启用 AOF 配置路径 AOF 文件&#x1f4c3; AOF 的写回策略 AOF 的重写机制 优点 缺点 RDB & AOF 优先级 终极方案&#xff1a;RDB AOF 混合方…

城市轨道交通自动售检票系统

概述 城市轨道交通自动售检票系统&#xff08;AFC&#xff09;是基于计算机、通信、网络、自动控制等技术&#xff0c;实现轨道交通售票、检票、计费、收费、统计、清分、管理等全过程的自动化系统。可以提高轨道交通的运营效率&#xff0c;满足乘客的快速出行需求&#xff0c…

看完张一鸣近十年微博,我总结了这些成长特质

从程序员到 CEO 关注我的朋友&#xff0c;很多都是技术背景&#xff0c;之前在一个知乎回答里提到过&#xff0c;技术人在创业过程中并不占优势。 编程和创业是两个不同的体系&#xff0c;大部分技术工程师在工作中&#xff0c;解决的往往是一个限定的问题&#xff0c;而创业是…

【分享】ChatGPT的key,用key免费使用ChatGPT(每天更新)

1、ChatGPT用法总结&#xff1a; 自动化文本生成&#xff1a;可以用GPT生成文章、新闻、文本摘要&#xff0c;甚至小说、诗歌等文学作品。语音生成&#xff1a;结合语音合成技术&#xff0c;GPT可以生成自然流畅的语音&#xff0c;可以用于语音助手、交互式语音应用等。问答系统…

MobileViT神经网络模型

官方源码(Pytorch实现) : https://github.com/apple/ml-cvnets 原文链接&#xff1a;https://blog.csdn.net/qq_37541097/article/details/126715733 霹雳吧啦Wz从ml-evnets仓库中剥离的代码: deep-learning-for-image-processing/pytorch_classification/MobileViT at master…

AWE 2023:科技与艺术的结晶 三星展台亮点回顾

2023年4月27~30日&#xff0c;AWE 2023中国家电及消费电子博览会在上海新国际博览中心盛大举行。 作为全球三大消费电子展之一&#xff0c;每一年的AWE都汇聚了全球家电及消费电子领域最前沿、最尖端的科技和产品&#xff0c;因而向来都被业界人士视为整个行业的风向标。本届AW…

【读书笔记】《深入浅出数据分析》

我最大的收获 试想你在经历一场英语考试&#xff0c;还有两分钟就要交卷了&#xff0c;而你还没有开始写作文。此时&#xff0c;你会怎么做&#xff1f; 利用2分钟时间写出的第一段&#xff0c;还是只写关键句子&#xff0c;搭出文章的开头、过程、结尾&#xff1f; 后者更加明…

【LeetCode】91. 解码方法

91. 解码方法&#xff08;中等&#xff09; 思路 这其实是一道字符串类的动态规划题&#xff0c;不难发现对于字符串s的某个位置i而言&#xff0c;我们只关心「位置 i 自己能否形成独立 item」和「位置 i 能够与上一位置&#xff08;i-1&#xff09;能否形成item 」&#xff0c…