给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址正好由四个整数(每个整数位于 0 到 255 之间组成),整数之间用 ‘.’ 分隔。
示例:
输入: “25525511135”
输出: [“255.255.11.135”, “255.255.111.35”]
链接:https://leetcode-cn.com/problems/restore-ip-addresses
==================================================
方法一:递归
思路与算法
由于我们需要找出所有可能复原出的 IP 地址,因此可以考虑使用递归的方法,对所有可能的字符串分隔方式进行搜索,并筛选出满足要求的作为答案。
设题目中给出的字符串为 ss。我们用递归函数 \textit{dfs}(\textit{segId}, \textit{segStart})dfs(segId,segStart) 表示我们正在从 s[\textit{segStart}]s[segStart] 的位置开始,搜索 IP 地址中的第 \textit{segId}segId 段,其中 \textit{segId} \in {0, 1, 2, 3}segId∈{0,1,2,3}。由于 IP 地址的每一段必须是 [0, 255][0,255] 中的整数,因此我们从 \textit{segStart}segStart 开始,从小到大依次枚举当前这一段 IP 地址的结束位置 \textit{segEnd}segEnd。如果满足要求,就递归地进行下一段搜索,调用递归函数 \textit{dfs}(\textit{segId} + 1, \textit{segEnd} + 1)dfs(segId+1,segEnd+1)。
特别地,由于 IP 地址的每一段不能有前导零,因此如果 s[\textit{segStart}]s[segStart] 等于字符 00,那么 IP 地址的第 \textit{segId}segId 段只能为 00,需要作为特殊情况进行考虑。
在递归搜索的过程中,如果我们已经得到了全部的 44 段 IP 地址(即 \textit{segId} = 4segId=4),并且遍历完了整个字符串(即 \textit{segStart} = |s|segStart=∣s∣,其中 |s|∣s∣ 表示字符串 ss 的长度),那么就复原出了一种满足题目要求的 IP 地址,我们将其加入答案。在其它的时刻,如果提前遍历完了整个字符串,那么我们需要结束搜索,回溯到上一步。
链接:https://leetcode-cn.com/problems/restore-ip-addresses/solution/fu-yuan-ipdi-zhi-by-leetcode-solution/
======================================================
要注意循环终止的几个条件:
1、如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
2、如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
3、由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
下面两段话的等价的都是为了判断addr的值是否在0 - 255之间
addr = addr * 10 + (ord(s[segEnd]) - ord(“0”))
if 0 < addr <= 0xFF:
我将其进行了改动便于理解
addr = addr * 10 + int(s[segEnd])
if 0 < addr <= 255:
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
# 递归
SEG_COUNT = 4
ans = list()
segments = [0] * SEG_COUNT #
def dfs(segId: int, segStart: int): # segId 0123,segStart 遍历到的字符位置
# 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
if segId == SEG_COUNT:
if segStart == len(s):
ipAddr = ".".join(str(seg) for seg in segments)
ans.append(ipAddr)
return
# 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
if segStart == len(s):
return
# 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
if s[segStart] == "0":
segments[segId] = 0
dfs(segId + 1, segStart + 1)
# 一般情况,枚举每一种可能性并递归
addr = 0
for segEnd in range(segStart, len(s)): # 开始到结尾 segEnd
# addr = addr * 10 + (ord(s[segEnd]) - ord("0")) # ord()函数主要用来返回对应字符的ascii码
# if 0 < addr <= 0xFF: # 0xFF:255
addr = addr * 10 + int(s[segEnd]) # ord()函数主要用来返回对应字符的ascii码
if 0 < addr <= 255: # 0xFF:255
segments[segId] = addr #
dfs(segId + 1, segEnd + 1)
else:
break
dfs(0, 0)
return ans