题目 93.复原IP地址
问题描述
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 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 地址。
示例 1:
输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]
示例 2:
输入:s = “0000”
输出:[“0.0.0.0”]
示例 3:
输入:s = “1111”
输出:[“1.1.1.1”]
解题思路
-
我们需要理解一个有效的 IP 地址是什么样的。一个 IP 地址由四个介于 0-255 的数字组成,每两个数字之间用"."分隔。例如,"255.255.255.255"就是一个有效的 IP 地址。
-
主要的步骤包括
- 切分字符串:我们需要将给定的字符串切分成四个部分,每个部分代表 IP 地址的一个数字。
-检查有效性:
段位以0为开头的数字不合法(长度大于1的情况下开头数字为0)
段位如果大于255了不合法(转整形)
- 切分字符串:我们需要将给定的字符串切分成四个部分,每个部分代表 IP 地址的一个数字。
-
这是到切割问题,可以参考131 分割回文串
-
树形结构:
代码结构:
代码
from typing import List
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
result = [] # 用来存储所有找到的有效 IP 地址
# 长度验证,如果 s 的长度小于 4 或大于 12,不可能形成有效的 IP 地址
if len(s)<4 or len(s)>12:
return result
self.backtracking(s, 0, 0, "", result)
return result
def backtracking(self, s, start, pointNum, path, result):
# 如果已经放置了 3 个点,并且消耗完了字符串,那么剩余的部分如果合法,就应该直接作为最后一段添加到结果中
if pointNum == 4 and start == len(s):
result.append(path[:-1]) # 除去末尾的 '.'
return
# 如果已经放置了 4 个点但是还没有消耗完字符串,或者消耗完了字符串但是还没放完点,这是不合法的,所以直接返回
if pointNum == 4:
return
# 尝试在 s 中从 start 开始的每一个位置放置点
for i in range(start ,len(s) ):
if self.isValid(s[start:i+1]): # 这里传入的是 s 的一个子串,而不是左右端点
self.backtracking(s, i+1, pointNum + 1, path + s[start:i+1] + ".", result)
def isValid(self, s): # 这里只需要传入一个字符串就好了
# 如果子串的长度大于 1 并且起始字符是 '0',那么这个子串不是合法的 IP 地址段
if len(s) > 1 and s[0] == '0':
return False
# 把字符型数字转换为整型数字,用来和 255 比较
num = int(s)
# 如果 num 大于 255,那么这个子串不是合法的 IP 地址段
if num > 255:
return False
return True
疑问
复杂度分析
题目 78.子集
问题描述
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
解题思路
- 注意去重部分
是对path进行深拷贝,不要弄错了
代码
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
result=[[]]
self.backtracking(nums,0,[],result)
return result
def backtracking(self,nums,startIndex,path,result):
#end logic
if len(path)>0:
result.append(path[:])
#single layer's logic
for i in range(startIndex,len(nums)):
path.append(nums[i])
self.backtracking(nums,i+1,path,result)
#backtracking
path.pop()
复杂度分析
题目 90.子集II
问题描述
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
解题思路
- 本题子集不用看顺序,但是设计重复问题,所以排序。如果是涉及到顺序问题那可以用hashset,或者usedlist。
- 定义一个辅助函数(回溯函数):这个函数将会采用回溯的方式生成所有的子集。这个函数需要记录当前的子集(path),以及我们正在处理的输入数组的位置(startIndex)。
- 处理重复元素:在尝试添加元素到path中的时候,我们需要检查当前元素是否和上一个元素相同。如果相同,我们只有在这是我们在这一层递归中第一次遇到这个元素时才添加它,否则我们就跳过这个元素。这样我们就可以避免生成重复的子集。
代码
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result=[[]]
self.backtracking(nums,0,[],result)
return result
def backtracking(self,nums,startIndex,path,result):
#end logic
if len(path)>0:
result.append(path[:])
#single layer's logic
for i in range(startIndex,len(nums)):
if i > startIndex and nums[i]==nums[i-1] :
continue
path.append(nums[i])
self.backtracking(nums,i+1,path,result)
#backtracking
path.pop()