有效 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
中的任何数字。你可以按任何顺序返回答案。
示例:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
引用:
原文链接:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html
题目链接:https://leetcode.cn/problems/restore-ip-addresses/description/
视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/
和切割回文串类似,但是多了一些判断条件。
我们需要一个判断IP是否有效的函数,这个函数比较简单,不做过多解释。
递归三部曲:
主要参数和返回值:
startIndex
。终止条件:
我们的IP地址是由4段数字组成,当 len(self.path) == 4
时,说明我们已经得到了完整的IP地址。然后我们来判断其实位置是否等于字符串 s
的长度,来判断我们所有的原材料是否都用完(题目要求不能有剩余)。
单层递归的逻辑:
和切割字符串一样
代码:
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
self.result = []
self.path = []
self.backtracking(s, 0)
return self.result
def backtracking(self, s, startIndex):
if len(self.path) == 4:
if startIndex == len(s):
self.result.append('.'.join(self.path))
return
for i in range(startIndex, min(startIndex + 3, len(s))):
cur_s = s[startIndex:i + 1]
if self.is_legal(cur_s):
self.path.append(cur_s)
self.backtracking(s, i + 1)
self.path.pop()
def is_legal(self, num):
if len(num) > 1 and num[0] == '0':
return False
return 0 <= int(num) <= 255
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
引用:
原文链接:https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html
题目链接:https://leetcode.cn/problems/subsets/description/
视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci/
和组合问题差不多。
组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
这里我们其实可以不需要终止条件了,其实可以不需要加终止条件,因为startIndex >= nums.size(),本层for循环本来也结束了。
因为要收集的是所有结点而不是叶子结点,所以保存结果的代码不能放在终止条件里。
代码:
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
result = []
path = []
def backtracking(start_index):
# 每次进入回溯函数时,当前的 path 都是一个子集
result.append(path[:])
for i in range(start_index, len(nums)):
# 做出选择,将当前元素加入 path
path.append(nums[i])
# 递归调用,继续处理下一个元素
backtracking(i + 1)
# 撤销选择,回溯到上一步
path.pop()
backtracking(0)
return result
给你一个整数数组 nums
,其中可能包含重复元素,请你返回该数组所有可能的 子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
引用:
原文链接:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html
题目链接:https://leetcode.cn/problems/subsets-ii/description/
视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J/
LeetCode 第 90 题 “子集 II” 与第 78 题 “子集” 的区别在于,给定的数组中可能包含重复元素,要求返回的子集不能有重复。
为了避免生成重复的子集,我们可以先对数组进行排序,这样相同的元素会相邻。在回溯过程中,如果当前元素和前一个元素相同,并且不是在处理该元素的第一个出现位置(即 i > start_index),就跳过这个元素,以此来避免生成重复的子集。
这种去重实际上是 数层去重,因为在同一层中,不能出现相同的元素,但是在同一个 树枝上,可以出现。
代码:
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
result = []
path = []
# 对数组进行排序,让相同元素相邻
nums.sort()
def backtracking(start_index):
# 每次进入回溯函数时,当前的 path 都是一个子集
result.append(path[:])
for i in range(start_index, len(nums)):
# 跳过重复元素
if i > start_index and nums[i] == nums[i - 1]:
continue
# 做出选择,将当前元素加入 path
path.append(nums[i])
# 递归调用,继续处理下一个元素
backtracking(i + 1)
# 撤销选择,回溯到上一步
path.pop()
backtracking(0)
return result