返回
复原 IP 地址:巧用动态规划,简洁明了!
后端
2024-02-14 13:35:53
问题概述
给定一个由数字组成的字符串,可以将其划分为四个部分,每部分都是一个数字(0 到 255 之间),且不能含有前导 0。组合这些部分可以得到一个 IP 地址。例如,"19216811"可以被划分为"192.168.1.1"或"192.168.11.1"。
动态规划解法
动态规划是一种自底向上的算法,可以将复杂问题分解为一系列子问题,然后逐步解决这些子问题,最终求得整体问题的解决方案。
在复原 IP 地址问题中,我们可以定义状态dp[i]
为从字符串第i
个字符开始到字符串末尾的所有可能的 IP 地址的集合。然后,我们可以通过以下递推关系来计算dp[i]
:
dp[i] = {}
(空集),如果i
大于等于字符串长度dp[i] = {a.b.c.d}
,如果i
等于字符串长度,其中a
,b
,c
,d
都是有效的 IP 地址段dp[i] = {a.b.c.d}
,如果i
小于字符串长度,且字符串第i
个字符到i+3
个字符组成的数字是一个有效的 IP 地址段,并且dp[i+4]
非空
以上递推关系的含义是:如果字符串第i
个字符到i+3
个字符组成的数字是一个有效的 IP 地址段,并且从第i+4
个字符开始到字符串末尾的所有可能的 IP 地址的集合非空,那么从第i
个字符开始到字符串末尾的所有可能的 IP 地址的集合就是由"a.b.c.d"
组成的集合,其中"a"
, "b"
, "c"
, "d"
都是有效的 IP 地址段。
代码示例
def restore_ip_addresses(s):
"""
:type s: str
:rtype: List[str]
"""
# 定义状态dp[i]为从字符串第i个字符开始到字符串末尾的所有可能的IP地址的集合
dp = [set() for _ in range(len(s) + 1)]
# 初始化dp[len(s)]为{}(空集)
dp[len(s)] = {""}
# 从后往前计算dp[i]
for i in range(len(s) - 1, -1, -1):
# 如果字符串第i个字符到i+3个字符组成的数字是一个有效的IP地址段
if 0 <= int(s[i:i + 1]) <= 255:
# 将dp[i+4]中的所有IP地址与s[i:i+1]连接起来,得到dp[i]中的所有IP地址
for ip_address in dp[i + 1]:
dp[i].add(s[i:i + 1] + "." + ip_address)
# 如果字符串第i个字符到i+2个字符组成的数字是一个有效的IP地址段
if 0 <= int(s[i:i + 2]) <= 255:
# 将dp[i+3]中的所有IP地址与s[i:i+2]连接起来,得到dp[i]中的所有IP地址
for ip_address in dp[i + 2]:
dp[i].add(s[i:i + 2] + "." + ip_address)
# 如果字符串第i个字符到i+3个字符组成的数字是一个有效的IP地址段
if 0 <= int(s[i:i + 3]) <= 255:
# 将dp[i+4]中的所有IP地址与s[i:i+3]连接起来,得到dp[i]中的所有IP地址
for ip_address in dp[i + 3]:
dp[i].add(s[i:i + 3] + "." + ip_address)
# 返回dp[0]中的所有IP地址
return list(dp[0])
结语
复原 IP 地址问题是一个经典的算法题,可以考察考生的动态规划能力和对字符串的处理能力。本文介绍的动态规划解法简洁明了,易于理解和实现。希望这篇文章能帮助你更好地理解复原 IP 地址问题,并掌握动态规划的思想和方法。