leetCode 93.复原 IP 地址 + 回溯算法 + 图解 + 笔记

news2024/11/16 9:47:15

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

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

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

相关文章

信贷销售经理简历模板

这份简历内容&#xff0c;以信贷销售经理招聘需求为背景&#xff0c;我们制作了1份全面、专业且具有参考价值的简历案例&#xff0c;大家可以灵活借鉴。 信贷销售经理简历模板在线编辑下载&#xff1a;百度幻主简历 求职意向 求职类型&#xff1a;全职 意向岗位&#xff…

【隐私计算】VOLE (Vector Oblivious Linear Evaluation)学习笔记

近年来&#xff0c;VOLE&#xff08;向量不经意线性评估&#xff09;被用于构造各种高效安全多方计算协议&#xff0c;具有较低的通信复杂度。最近的CipherGPT则是基于VOLE对线性层进行计算。 1 VOLE总体设计 VOLE的功能如下&#xff0c;VOLE发送 Δ \Delta Δ和 b b b给send…

王者小游戏

游戏里的经验动物 Bear package beast; import sxt.GameFrame; public class Bear extends Beast {public Bear(int x, int y, GameFrame gameFrame) {super(x, y, gameFrame);setImg("C:\\Users\\辛欣\\OneDrive\\桌面\\王者荣耀图片(1)\\王者荣耀图片\\beast\\bear.jp…

从物理机到K8S:应用系统部署方式的演进及其影响

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享。 概述 随着科技的进步&#xff0c;软件系统的部署架构也在不断演进&#xff0c;从以前传统的物理机到虚拟机、Docker和Kubernetes&#xff0c;我们经历了一系列变化。 这些技术的引入…

liunx java 生成图片 中文显示不出来

使用java 生成图片,在图片上打的文字水印显示为一个方框,这种情况的原因,一般是liunx系统或者docker容器内,没有你在打文字水印时选择的字体 解决办法,先找一个免费的字体,比如 Alibaba-PuHuiTi-Regular.otf 然后使用字体 File newFileT new File("Alibaba-PuHuiTi-Re…

OSPF的8种状态机总结,小白必看!

OSPF概述 在OSPF网络中&#xff0c;为了交换路由信息&#xff0c;邻居设备之间首先要建立邻接关系&#xff0c;邻居&#xff08;Neighbors&#xff09;关系和邻接&#xff08;Adjacencies&#xff09;关系是两个不同的概念。 邻居关系 OSPF设备启动后&#xff0c;会通过OSPF…

Python streamlit指南,构建令人惊叹的可视化Web界面!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在当今数据驱动的世界中&#xff0c;构建交互式、美观且高效的数据可视化应用变得至关重要。而Streamlit&#xff0c;作为Python生态系统中为开发者提供了轻松创建Web应用的利器。 本文将深入探讨Streamlit的方…

Android Studio Giraffe版本遇到的问题

背景 上周固态硬盘挂了&#xff0c;恢复数据之后&#xff0c;重新换了新的固态安装了Win11系统&#xff0c;之前安装的是Android Studio 4.x的版本&#xff0c;这次也是趁着新的系统安装新的Android开发工具。 版本如下&#xff1a; 但是打开以前的Android旧项目时&#xff…

Informer辅助笔记:data/dataloader.py

以WTH为例 import os import numpy as np import pandas as pdimport torch from torch.utils.data import Dataset, DataLoader # from sklearn.preprocessing import StandardScalerfrom utils.tools import StandardScaler from utils.timefeatures import time_featuresim…

动态:class和:style绑定

1. 在应用界面中, 某个(些)元素的样式是变化的 class/style绑定就是专门用来实现动态样式效果的技术 2. 动态class绑定 :class等号后的变量值 可以是字符串 :class等号后 可以是对象 :class等号后 可以是数组 3. 动态style绑定 :style"{ color: myPinkColor, fontS…

功能测试换工作不被认可?那你缺少这5点建议

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

asla四大开源组件应用示例(alsa-lib、alsa-utils、alsa-tools、alsa-plugins)

文章目录 alsa设备文件/dev/snd//sys/class/sound/proc/asoundalsa-lib示例1alsa-utilsalsa-toolsalsa-plugins参考alsa设备文件 /dev/snd/ alsa设备文件目录位于,/dev/snd,如下所示 root@xboard:~#ls /dev/snd -l total 0 drwxr-xr-x 2 root root 60 Nov 6 2023 …

速达软件全系产品 RCE漏洞复现

0x01 产品简介 速达软件是中小企业管理软件第一品牌和行业领导者,是128万家企业用户忠实的选择。14年来速达致力于进销存软件、ERP软件、财务软件、CRM软件等管理软件的研发和服务。 0x02 漏洞概述 速达软件全系产品存在任意文件上传漏洞&#xff0c;未经身份认证得攻击者可以…

flask web开发学习之初识flask(二)

文章目录 一、创建程序实例并注册路由1. 为视图绑定绑定多个URL2. 动态URL 二、启动开发服务器1. 自动发现程序实例2. 管理环境变量3. 使用pycharm运行服务器4. 更多的启动选项5. 设置运行环境6. 调试器7. 重载器 一、创建程序实例并注册路由 app.py # 从flask包中导入flask类…

selenium元素定位方法之xpath

什么是xpath&#xff1f; XPath是XML的路径语言&#xff0c;通俗一点讲就是通过元素的路径来查找到这个标签元素XPath使用路径表达式在XML文档中进行导航 普通语法 注意&#xff01; 1.xpath中的值用引号引起来时&#xff0c;在代码中要注意区分&#xff0c;内单外双&#xf…

Pandas教程07:DataFrame数据中apply参数自定义运算的用法

DataFrame.apply()方法主要用于调用每个Series的函数。此函数可以是一个Python的函数&#xff0c;或者是lambda函数。此函数可以接收一个函数作为输入&#xff0c;并应用于DataFrame的每一列。 以下是一些DataFrame.apply()的示例用法&#xff1a; # Author : 小红牛 # 微信公…

深度解析 Spring Security 自定义异常失效问题:源码剖析与解决方案

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

【docker系列】docker实战之部署SpringBoot项目

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

行行AI董事长李明顺:今天每个人都可以成为AI应用的创业者

“ AI创业的核心在于真正介入到应用层面&#xff0c;AI应该成为真正的应用支撑。 ” 整理 | 王娴 编辑 | 云舒 出品&#xff5c;极新 2023年11月28日&#xff0c;极新AIGC行业峰会在北京东升国际科学园顺利召开&#xff0c;行行AI董事长李明顺先生在会上做了题为《从大模型…

如何做好前端单元测试?字节5年测试老司机是这样说的!

近几年&#xff0c;前端发展越来越迅猛&#xff0c;各类框架层出不穷&#xff0c;前端实现的业务逻辑也越来越复杂&#xff0c;前端单元测试也越来越受重视&#xff0c;包括百度在内的一些大厂在面试中也会问到单元测试相关的题目。那么前端应该如何做好单元测试&#xff1f; 什…