093.复原 IP 地址
作者:沉默王二
发布时间:2023-10-27T16:53:37.294+0800
本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记),访问地址和密码:https://t.zsxq.com/6iuzn6I
题意
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
- 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "[email protected] " 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
难度
中等
示例
示例 1:
输入:s="25525511135"
示例 2:
输入:s="0000"
示例 3:
输入:s="101023"
分析
本题我们先来观察数据范围,可以发现,就算是每段都为三位的 IP 地址(255),最多也只有长度为 12 的字符串生成,对吧?
所以,这么小的数据范围,我们不必大费周章考虑别的算法,直接采用搜索算法即可,对于本题,深度优先搜索是非常不错的选择。
深度优先搜索(Depth-First Search,简称DFS)是一种用于遍历或搜索树或图的算法。
首先我们来确定一下边界条件,用cnt来记录 IP 地址段(用.号分割开)的总数,并用anss[]来记录每个段,等cnt == 4时,代表 IP 地址已经切割完成,如果刚好也遍历完了整个字符串,且没有非法的情况,就可以将anss[]加入最后的答案。
其次,还有一个点需要注意,那就是遇到0的情况,我们该如何抉择?
当然是直接加入anss[],并且向后继续访问输入s。因为0不能作为段的开头。
如果是非零的情况,则需要枚举。
从当前位置开始枚举,并且用num来记录值,当值大于255的时候停止枚举,然后将num加入anss[],并增加一次段的数目cnt++,再然后进入下一次搜索。
多说无益,不如我们仔细看看代码:
classSolution{
int[]anss=newint[4];//存储每次递归得到的IP段
publicList
publicvoiddfs(Strings,intcnt,intpos){//如果已经得到4段IP地址if(cnt==4){//并且已经处理完整个字符串if(pos==s.length()){StringBuildertemp=newStringBuilder();for(inti=0;i<4;i++){temp.append(anss[i]);if(i!=3){temp.append(".");}}ans.add(temp.toString());}return;}//如果当前位置已经超过字符串长度if(pos==s.length()){return;}//如果当前位置字符为'0'if(s.charAt(pos)=='0'){anss[cnt]=0;//直接保存该段IP为0dfs(s,cnt+1,pos+1);//继续递归}else{intnum=0;//用于暂存当前段的IP地址//尝试每一种可能的组合for(inti=pos;i<s.length();i++){num=num*10+(s.charAt(i)-'0');//检查当前数字是否有效if(num>0&&num<=255){anss[cnt]=num;//保存当前段IP地址dfs(s,cnt+1,i+1);//继续递归}else{break;//如果当前数字不再合法范围内,直接跳出}}}}}
题解中有一个小的知识点,对于任何从'0'到'9'的数字字符,charAt(i) - '0'都会返回其对应的整数值。
当输入是"25525511135"时我们来模拟一下整个题解过程。
我们开始在s的开头执行dfs:
- cnt = 0, pos = 0
- 第一个数字为'2',不为'0',所以可以尝试分成1-3位数的部分。
- 取1位数: 2
- 取2位数: 25
- 取3位数: 255 (合法,因为它<=255)
- 对于上述的每一个数值,我们都将继续递归地寻找下一部分。
- 当我们取第一部分为255时(其他的取值也类似),继续深入搜索:
- cnt = 1, pos = 3
- 下一个数字为'2',同样,我们可以尝试1-3位数。
- 取1位数: 2
- 取2位数: 25
- 取3位数: 255
- 如果我们继续取255作为第二部分,那么进一步深入:
- cnt = 2, pos = 6
- 下一个数字为'1'
- 取1位数: 1
- 取2位数: 11
- 取3位数: 111
- 如果我们继续以111为第三部分,那么再次深入:
- cnt = 3, pos = 9
- 取1位数: 3
- 取2位数: 35
- 因为pos已经达到字符串末尾,我们不能再取3位数。
- 于是,我们得到一个合法的IPv4地址:255.255.111.35。
同理,我们可以通过所有可能的分割方式,使用DFS来查找所有合法的IPv4地址。最终,对于输入25525511135,题解将生成以下两个合法的IPv4地址:
- 255.255.11.135
- 255.255.111.35
整个过程就是一个标准的DFS,从前到后地搜索字符串,每一步都尝试1到3个字符,确保每一步都符合IPv4的规则。
我们来看一下整个题解的效率:
如果感兴趣的话,还可以通过 ACM 输入输出的方式在 Intellij IDEA 中进行调试。
importjava.util.ArrayList;
importjava.util.Scanner;
publicclassRestoreIPAddresses{List
publicList
publicvoiddfs(Strings,intcnt,intpos){if(cnt==4){if(pos==s.length()){StringBuildertemp=newStringBuilder();for(inti=0;i<4;i++){temp.append(anss[i]);if(i!=3){temp.append(".");}}ans.add(temp.toString());}return;}if(pos==s.length()){return;}if(s.charAt(pos)=='0'){anss[cnt]=0;dfs(s,cnt+1,pos+1);}else{intnum=0;for(inti=pos;i<s.length();i++){num=num*10+(s.charAt(i)-'0');if(num>0&&num<=255){anss[cnt]=num;dfs(s,cnt+1,i+1);}else{break;}}}}
publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入给定的IP字符串:");Strings=scanner.next();RestoreIPAddressessolution=newRestoreIPAddresses();List
输入输出的结果如下所示:
总结
搜索类的题目通常并非难题,重要的如何将我们内心中模拟的过程完美的复现出来,而多练习,是我们提高这类解题技巧的最好方式。
力扣链接:https://leetcode.cn/problems/restore-ip-addresses/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。
一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 3800 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!
本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记),访问地址和密码:https://t.zsxq.com/6iuzn6I
题意
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
- 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "[email protected] " 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
难度
中等
示例
示例 1:
输入:s="25525511135"
示例 2:
输入:s="0000"
示例 3:
输入:s="101023"
分析
本题我们先来观察数据范围,可以发现,就算是每段都为三位的 IP 地址(255),最多也只有长度为 12 的字符串生成,对吧?
所以,这么小的数据范围,我们不必大费周章考虑别的算法,直接采用搜索算法即可,对于本题,深度优先搜索是非常不错的选择。
深度优先搜索(Depth-First Search,简称DFS)是一种用于遍历或搜索树或图的算法。
首先我们来确定一下边界条件,用cnt来记录 IP 地址段(用.号分割开)的总数,并用anss[]来记录每个段,等cnt == 4时,代表 IP 地址已经切割完成,如果刚好也遍历完了整个字符串,且没有非法的情况,就可以将anss[]加入最后的答案。
其次,还有一个点需要注意,那就是遇到0的情况,我们该如何抉择?
当然是直接加入anss[],并且向后继续访问输入s。因为0不能作为段的开头。
如果是非零的情况,则需要枚举。
从当前位置开始枚举,并且用num来记录值,当值大于255的时候停止枚举,然后将num加入anss[],并增加一次段的数目cnt++,再然后进入下一次搜索。
多说无益,不如我们仔细看看代码:
classSolution{
int[]anss=newint[4];//存储每次递归得到的IP段
publicList
publicvoiddfs(Strings,intcnt,intpos){//如果已经得到4段IP地址if(cnt==4){//并且已经处理完整个字符串if(pos==s.length()){StringBuildertemp=newStringBuilder();for(inti=0;i<4;i++){temp.append(anss[i]);if(i!=3){temp.append(".");}}ans.add(temp.toString());}return;}//如果当前位置已经超过字符串长度if(pos==s.length()){return;}//如果当前位置字符为'0'if(s.charAt(pos)=='0'){anss[cnt]=0;//直接保存该段IP为0dfs(s,cnt+1,pos+1);//继续递归}else{intnum=0;//用于暂存当前段的IP地址//尝试每一种可能的组合for(inti=pos;i<s.length();i++){num=num*10+(s.charAt(i)-'0');//检查当前数字是否有效if(num>0&&num<=255){anss[cnt]=num;//保存当前段IP地址dfs(s,cnt+1,i+1);//继续递归}else{break;//如果当前数字不再合法范围内,直接跳出}}}}}
题解中有一个小的知识点,对于任何从'0'到'9'的数字字符,charAt(i) - '0'都会返回其对应的整数值。
当输入是"25525511135"时我们来模拟一下整个题解过程。
我们开始在s的开头执行dfs:
- cnt = 0, pos = 0
- 第一个数字为'2',不为'0',所以可以尝试分成1-3位数的部分。
- 取1位数: 2
- 取2位数: 25
- 取3位数: 255 (合法,因为它<=255)
- 对于上述的每一个数值,我们都将继续递归地寻找下一部分。
- 当我们取第一部分为255时(其他的取值也类似),继续深入搜索:
- cnt = 1, pos = 3
- 下一个数字为'2',同样,我们可以尝试1-3位数。
- 取1位数: 2
- 取2位数: 25
- 取3位数: 255
- 如果我们继续取255作为第二部分,那么进一步深入:
- cnt = 2, pos = 6
- 下一个数字为'1'
- 取1位数: 1
- 取2位数: 11
- 取3位数: 111
- 如果我们继续以111为第三部分,那么再次深入:
- cnt = 3, pos = 9
- 取1位数: 3
- 取2位数: 35
- 因为pos已经达到字符串末尾,我们不能再取3位数。
- 于是,我们得到一个合法的IPv4地址:255.255.111.35。
同理,我们可以通过所有可能的分割方式,使用DFS来查找所有合法的IPv4地址。最终,对于输入25525511135,题解将生成以下两个合法的IPv4地址:
- 255.255.11.135
- 255.255.111.35
整个过程就是一个标准的DFS,从前到后地搜索字符串,每一步都尝试1到3个字符,确保每一步都符合IPv4的规则。
我们来看一下整个题解的效率:
如果感兴趣的话,还可以通过 ACM 输入输出的方式在 Intellij IDEA 中进行调试。
importjava.util.ArrayList;
importjava.util.Scanner;
publicclassRestoreIPAddresses{List
publicList
publicvoiddfs(Strings,intcnt,intpos){if(cnt==4){if(pos==s.length()){StringBuildertemp=newStringBuilder();for(inti=0;i<4;i++){temp.append(anss[i]);if(i!=3){temp.append(".");}}ans.add(temp.toString());}return;}if(pos==s.length()){return;}if(s.charAt(pos)=='0'){anss[cnt]=0;dfs(s,cnt+1,pos+1);}else{intnum=0;for(inti=pos;i<s.length();i++){num=num*10+(s.charAt(i)-'0');if(num>0&&num<=255){anss[cnt]=num;dfs(s,cnt+1,i+1);}else{break;}}}}
publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入给定的IP字符串:");Strings=scanner.next();RestoreIPAddressessolution=newRestoreIPAddresses();List
输入输出的结果如下所示:
总结
搜索类的题目通常并非难题,重要的如何将我们内心中模拟的过程完美的复现出来,而多练习,是我们提高这类解题技巧的最好方式。
力扣链接:https://leetcode.cn/problems/restore-ip-addresses/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。
一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 3800 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!
本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记),访问地址和密码:https://t.zsxq.com/6iuzn6I
题意
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
- 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "[email protected] " 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
难度
中等
示例
示例 1:
输入:s="25525511135"
示例 2:
输入:s="0000"
示例 3:
输入:s="101023"
分析
本题我们先来观察数据范围,可以发现,就算是每段都为三位的 IP 地址(255),最多也只有长度为 12 的字符串生成,对吧?
所以,这么小的数据范围,我们不必大费周章考虑别的算法,直接采用搜索算法即可,对于本题,深度优先搜索是非常不错的选择。
深度优先搜索(Depth-First Search,简称DFS)是一种用于遍历或搜索树或图的算法。
首先我们来确定一下边界条件,用cnt来记录 IP 地址段(用.号分割开)的总数,并用anss[]来记录每个段,等cnt == 4时,代表 IP 地址已经切割完成,如果刚好也遍历完了整个字符串,且没有非法的情况,就可以将anss[]加入最后的答案。
其次,还有一个点需要注意,那就是遇到0的情况,我们该如何抉择?
当然是直接加入anss[],并且向后继续访问输入s。因为0不能作为段的开头。
如果是非零的情况,则需要枚举。
从当前位置开始枚举,并且用num来记录值,当值大于255的时候停止枚举,然后将num加入anss[],并增加一次段的数目cnt++,再然后进入下一次搜索。
多说无益,不如我们仔细看看代码:
classSolution{
int[]anss=newint[4];//存储每次递归得到的IP段
publicList
publicvoiddfs(Strings,intcnt,intpos){//如果已经得到4段IP地址if(cnt==4){//并且已经处理完整个字符串if(pos==s.length()){StringBuildertemp=newStringBuilder();for(inti=0;i<4;i++){temp.append(anss[i]);if(i!=3){temp.append(".");}}ans.add(temp.toString());}return;}//如果当前位置已经超过字符串长度if(pos==s.length()){return;}//如果当前位置字符为'0'if(s.charAt(pos)=='0'){anss[cnt]=0;//直接保存该段IP为0dfs(s,cnt+1,pos+1);//继续递归}else{intnum=0;//用于暂存当前段的IP地址//尝试每一种可能的组合for(inti=pos;i<s.length();i++){num=num*10+(s.charAt(i)-'0');//检查当前数字是否有效if(num>0&&num<=255){anss[cnt]=num;//保存当前段IP地址dfs(s,cnt+1,i+1);//继续递归}else{break;//如果当前数字不再合法范围内,直接跳出}}}}}
题解中有一个小的知识点,对于任何从'0'到'9'的数字字符,charAt(i) - '0'都会返回其对应的整数值。
当输入是"25525511135"时我们来模拟一下整个题解过程。
我们开始在s的开头执行dfs:
- cnt = 0, pos = 0
- 第一个数字为'2',不为'0',所以可以尝试分成1-3位数的部分。
- 取1位数: 2
- 取2位数: 25
- 取3位数: 255 (合法,因为它<=255)
- 对于上述的每一个数值,我们都将继续递归地寻找下一部分。
- 当我们取第一部分为255时(其他的取值也类似),继续深入搜索:
- cnt = 1, pos = 3
- 下一个数字为'2',同样,我们可以尝试1-3位数。
- 取1位数: 2
- 取2位数: 25
- 取3位数: 255
- 如果我们继续取255作为第二部分,那么进一步深入:
- cnt = 2, pos = 6
- 下一个数字为'1'
- 取1位数: 1
- 取2位数: 11
- 取3位数: 111
- 如果我们继续以111为第三部分,那么再次深入:
- cnt = 3, pos = 9
- 取1位数: 3
- 取2位数: 35
- 因为pos已经达到字符串末尾,我们不能再取3位数。
- 于是,我们得到一个合法的IPv4地址:255.255.111.35。
同理,我们可以通过所有可能的分割方式,使用DFS来查找所有合法的IPv4地址。最终,对于输入25525511135,题解将生成以下两个合法的IPv4地址:
- 255.255.11.135
- 255.255.111.35
整个过程就是一个标准的DFS,从前到后地搜索字符串,每一步都尝试1到3个字符,确保每一步都符合IPv4的规则。
我们来看一下整个题解的效率:
如果感兴趣的话,还可以通过 ACM 输入输出的方式在 Intellij IDEA 中进行调试。
importjava.util.ArrayList;
importjava.util.Scanner;
publicclassRestoreIPAddresses{List
publicList
publicvoiddfs(Strings,intcnt,intpos){if(cnt==4){if(pos==s.length()){StringBuildertemp=newStringBuilder();for(inti=0;i<4;i++){temp.append(anss[i]);if(i!=3){temp.append(".");}}ans.add(temp.toString());}return;}if(pos==s.length()){return;}if(s.charAt(pos)=='0'){anss[cnt]=0;dfs(s,cnt+1,pos+1);}else{intnum=0;for(inti=pos;i<s.length();i++){num=num*10+(s.charAt(i)-'0');if(num>0&&num<=255){anss[cnt]=num;dfs(s,cnt+1,i+1);}else{break;}}}}
publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入给定的IP字符串:");Strings=scanner.next();RestoreIPAddressessolution=newRestoreIPAddresses();List
输入输出的结果如下所示:
总结
搜索类的题目通常并非难题,重要的如何将我们内心中模拟的过程完美的复现出来,而多练习,是我们提高这类解题技巧的最好方式。
力扣链接:https://leetcode.cn/problems/restore-ip-addresses/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。
一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 3800 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!
知识星球
扫码加入星球
查看更多优质内容
https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412