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"]

题目要求:给我们个字符串,切割成一个合法的IP地址(IPv4形式)

思路和分析(O_O)?  

  • 切割问题可以使用回溯搜索法把所有可能性搜出来
  • 切割问题可以抽象树形结构
  • 判断子串是否合法

(一)判断子串是否合法,主要考虑三点: 

  • 1)以0开头的数字不合法
if(s[start] == '0' && start != end) { // 0开头的数字不合法
    return false;
}
  • 2)有非正整数字符不合法
if(s[i]>'9' || s[i]<'0') { // 遇到非数字字符不合法
    return false;
}
  • 3)如果大于255不合法
if(num > 255) return false;// 如果大于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;
    }
    // num = num*10+(s[i]-'0');
    // "225" -> 2*10=20 
    //          20*10+2=22 
    //          22*10+5=225
    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) return false;// 如果大于255了,不合法
    }
    return true;
}

(二)回溯三部曲:

1.确定递归参数返回类型

  • startIndex:记录搜索的起始位置,是下一次递归分割的起始位置,可确保不会重复分割
  • pointNum:记录添加逗点的数量
void backtracking(string& s,int startIndex,int pointNum)

2.确定递归终止条件

  • leetCode 131.分割回文串是以切割线到最后作为终止条件
  • 本题是 IPv4 地址,故所给字符串会被分成 4段,所以以分割的段数作为终止条件
  • 如果最后一段,也就是第四段字符串合法,才加入结果集result
if(pointNum == 3) { // 逗点数量为3时,分隔结束
    // 判断第四段字符串是否合法,如果合法就放进result中
    if(isValid(s,startIndex,s.size()-1)) {
        result.push_back(s);
    }
    return;
}

3.单层搜索的逻辑

[startIndex, i] 这个区间可用来截取的子串,接着判断这个子串是否合法

  • 1)如果合法,则在其后加上符号'.' 来表示已经分割
  • 2)如果不合法直接结束本层循环,在图中表现为剪掉分支

递归和回溯的过程:

  • 递归调用时,下一层递归的 startIndex 要从 i + 2 开始(在字符串中加入分隔符'.'),还有pointNum++,表示分隔符的数量增加一个;
  • 回溯时,将刚刚加入的分隔符 . 删掉就行,还有 pointNum--
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;                     //不合法,直接结束本层for循环
}

C++代码:

/*
    切割问题可以使用回溯搜索法把所有可能性搜出来
    切割问题可以抽象为树形结构
    判断子串是否合法,主要考虑三点:
        1).以0为开头的数字不合法
        2).有非正整数字符不合法
        3).如果大于255了不合法

    回溯三部曲:
        1.确定递归参数和返回类型
            startIndex:记录搜索的起始位置,是下一次递归分割的起始位置,可确保不会重复分割
            pointNum:记录添加逗点的数量
        2.确定递归终止条件
            - leetCode 131.分割回文串是以切割线到最后作为终止条件
            - 本题是IPv4地址,故所给字符串会被分成4段,所以以分割的段数作为终止条件
        3.单层搜索的逻辑
            [startIndex, i] 这个区间可用来截取的子串,接着判断这个子串是否合法
            1).如果合法,则在其后加上符号'.' 来表示已经分割
            2).如果不合法就直接结束本层循环,在图中表现为剪掉分支
            递归和回溯的过程:
                递归调用时,下一层递归的startIndex要从 i + 2开始(在字符串中加入分隔符.),还有pointNum++,表示分隔符的数量增加一个
                回溯时,将刚刚加入的分隔符 . 删掉就行,还有pointNum--


*/  
class Solution {
public:
    vector<string>result;// 记录结果
    // 判断字符串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) return false;// 如果大于255了,不合法
        }
        return true;
    }
    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;                     //不合法,直接结束本层for循环
        }
    }
    vector<string> restoreIpAddresses(string s) {
        if(s.size() < 4 || s.size() > 12) return result; // 算是剪枝了
        backtracking(s,0,0);
        return result;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于AT89C51单片机的电子闹钟设计

1&#xff0e;设计任务 利用AT89C51单片机为核心控制元件,设计一个电子闹钟&#xff0c;设计的系统实用性强、操作简单&#xff0c;实现了智能化、数字化。 &#xff08;1&#xff09;按开始键自动进入时间显示&#xff0c;开始为0&#xff0c;按K1键进入更改时间&#xff0c…

代码随想录算法训练营 ---第五十一天

1.第一题&#xff1a; 简介&#xff1a; 本题相较于前几题状态复杂了起来&#xff0c;因为多了一个冷冻期。本题讲解可去代码随想录看&#xff0c;这里差不多只是加了些自己的理解。 动规五部曲&#xff0c;分析如下&#xff1a; 确定dp数组以及下标的含义 dp[i][j]&#x…

数据库应用:MongoDB 文档与索引管理

目录 一、理论 1.MongoDB文档管理 2.MongoDB索引管理 二、实验 1.MongoDB文档管理 2.MongoDB索引管理&#xff08;索引添加与删除&#xff09; 3.MongoDB索引管理&#xff08;全文索引&#xff09; 4.MongoDB索引管理&#xff08;多列索引&#xff09; 5.MongoDB索引管…

【办公软件】Outlook启动一直显示“正在启动”的解决方法

早上打开电脑Outlook2016以后&#xff0c;半个多小时了&#xff0c;一直显示这个界面&#xff1a; 解决办法 按WIN R键打开“运行”&#xff0c;输入如下命令&#xff1a; outlook.exe /safe 然后点击“确定” 这样就进入了Outlook的安全模式。 点击“文件”->“选项”-…

【智能家居】三、添加语音识别模块的串口读取功能点

语音识别模块SU-03T 串口通信线程控制代码 inputCommand.h&#xff08;输入控制指令&#xff09;voiceControl.c&#xff08;语音控制模块指令&#xff09;main.c&#xff08;主函数&#xff09;编译运行结果 语音识别模块SU-03T AI智能语音识别模块离线语音控制模块语音识别…

Oracle 单表插入/多表插入(Single Table Insert/Multi-table Insert)

数据库应用中&#xff0c;我们经常需要向表中插入数据&#xff0c;insert语句是最常用的数据插入方式&#xff0c;根据目标表的数量&#xff0c;可以分为单表插入和多表插入。 目录 一、 单表插入&#xff08;Single Table Insert&#xff09; 二、 多表插入&#xff08;Multi-…

Set集合的特点

Set系列集合特点&#xff1a; 无序&#xff1a;添加数据的顺序和获取出的数据顺序不一致&#xff1b;不重复&#xff1b;无索引&#xff1b; HashSet&#xff1a;无序&#xff0c;不重复&#xff0c;无索引 LinkedHashSet&#xff1a;有序&#xff0c;不重复&#xff0c;无索引…

DS八大排序之直接选择排序和堆排序

前言 上一期我们已经介绍了&#xff0c;排序、为什么要有排序以及排序在实际生活中的应用。并且介绍并实现了直接插入排序和它的优化即希尔排序~&#xff01;本期我们再来学习一组排序 ---- "选择排序"即直接选择排序和堆排序~&#xff01; 本期内容介绍 直接选择排…

【linux防火墙】设置开启路由转发,SNAT和DNAT转换原理及应用实操,添加自定义链归类iptables规则

目录 一、关于iptables规则的保存 1.1持久保存规则 1.2加载规则 1.3开机自动加载规则 1.4使用iptables-service软件来进行规则的保存和加载&#xff08;不建议使用&#xff09; 二、SNAT和DNAT的原理和应用 SNAT的原理与应用&#xff1a; DNAT的原理和应用&#xff1a; …

透彻理解二叉树中序遍历的应用

关卡名 二分搜索树 我会了✔️ 内容 1.有序数组转为二叉搜索树 ✔️ 2.寻找两个正序数组的中位数 ✔️ 1 有序数组转为二叉搜索树 LeetCode108 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度…

深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理&#x1f525;如果感觉博主的文章还不错的话&#xff…

全志XR806基于FreeRTOS下部署竞技机器人先进模糊控制器

前言 很荣幸参与到由“极术社区和全志在线联合组织”举办的XR806开发板试用活动。本人热衷于各种的开发板的开发&#xff0c;同时更愿意将其实现到具体项目中。秉承以上原则&#xff0c;发现大家的重心都放在开发中的环境构建过程&#xff0c;缺少了不少实际应用场景的运用&am…

【小布_ORACLE笔记】Part11-5 RMAN Backups

【小布_ORACLE笔记】Part11-5 RMAN Backups 文章目录 【小布_ORACLE笔记】Part11-5 RMAN Backups1. 增量备份&#xff08;Incremental Backups)1.1差异增量备份&#xff08;Differential Incremental Backup&#xff09;1.2累积增量备份&#xff08;Cumulative Incremental Bac…

记RocketMQ本地开发环境搭建始末

前言 最近工作中涉及到了RocketMQ的应用&#xff0c;为方便开发决定本地搭建一套RocketMQ的使用环境。 果然实践是个好东西... VMware虚拟环境搭建 这个网上有很多教程&#xff0c;只会比我写的详细有条理&#xff0c;这里就不在赘述了。 虚拟机搭建好之后每次重启电脑都无…

【投稿优惠、可EI检索】2024年机器人学习与自动化算法国际学术会议(IACRLAA 2024)

2024年机器人学习与自动化算法国际学术会议(IACRLAA 2024) 2024 International Academic Conference on Intelligent Control Systems and Robot Learning 一、【会议简介】 本届机器人学习与自动化算法国际学术会议(IACRLAA 2024)将于2024年1月23日在北京盛大开幕。这次会议将…

Vue3 Router跳转传参

最近遇到这个问题router跳转传参&#xff0c;真是要了老命了。 根据网上各位大神给出的方法&#xff0c;试了 import { useRouter } from vue-routerconst router useRouter()//1. 无法跳转 router.push(name:,params:{})//2. 可以跳转, 但需要在定义router同时定义占位符&a…

(五)基于高尔夫优化算法GOA求解无人机三维路径规划研究(MATLAB代码)

一、无人机模型简介&#xff1a; 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献&#xff1a; [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、高尔夫优化算法GOA简介 高尔夫优化算法…

react-flip-move结合array-move实现前端列表置顶效果

你有没有遇到这样的需求&#xff1f;点击左侧列表项&#xff0c;则像聊天会话窗口一样将被点击的列表项置顶。 如果只是单纯的置顶的话&#xff0c;直接使用array-move就可以实现了&#xff0c;但置顶效果多少有点突兀~ 先上代码&#xff0c;直接使用array-move的情况&#xf…

用于缓存一些固定名称的小组件

项目中&#xff0c;用于缓存姓名、地名、单位名称等一些较固定名称的id-name小组件。用于减少一些表的关连操作和冗余字段。优化代码结构。扩展也方便&#xff0c;写不同的枚举就行了。 具体用法&#xff1a; {NameCacheUser.USER.getName(userId);NameCacheUser.ACCOUNT.getN…

文心一言 VS 讯飞星火 VS chatgpt (146)-- 算法导论12.2 1题

一、用go语言&#xff0c;假设一棵二叉搜索树中的结点在1到 1000 之间&#xff0c;现在想要查找数值为 363 的结点。下面序列中哪个不是查找过的序列? a.2&#xff0c;252&#xff0c;401&#xff0c;398&#xff0c;330&#xff0c;344&#xff0c;397&#xff0c;363。 b.9…