跟随carl代码随想录刷题
语言:python
题目:给你一个整数数组 nums ,数组中的元素
互不相同。返回该数组所有可能的子集(幂集)。
解集不能 包含重复的子集。你可以按 任意顺序 返回解集。
👉示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
👉示例 2:
输入:nums = [0]
输出:[[],[0]]
组合问题和分割问题都是收集树的叶子节点
子集问题是找树的所有节点
本题终止条件可以不要,for循环结束后自动结束
if startIndex == len(nums):return注意:res.append(path[:]) # 是path[:],而不是path
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
def backtracking(nums, startIndex):
if path not in res:
res.append(path[:]) # 注意是path[:],而不是path
# 单层递归逻辑
for i in range(startIndex, len(nums)):
path.append(nums[i])
backtracking(nums, i+1)
path.pop()
backtracking(nums, 0)
return res
题目:给你一个整数数组 nums ,其中
可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
👉示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
👉示例 2:
输入:nums = [0]
输出:[[],[0]]
因为数组中元素存在重复,因此在单层逻辑编写的时候要进行树层去重判断:如果当前元素与前一个元素重复了,那就终止这层逻辑,即:终止对当前元素的操作。接着对下一个元素进行判断。
因此要注意两点:
.sort()if i > startIndex and nums[i] == nums[i-1]: continue注:[:]中,省略头部和尾部索引值,功能是复制列表。
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
nums.sort() # 剪枝之前先排序
def backtracking(nums, startIndex):
if path not in res:
res.append(path[:]) # 这里一定要写path[:],而不是path。
# 终止条件
if startIndex == len(nums):
return
# 单层递归逻辑
for i in range(startIndex, len(nums)):
# 树层去重
if i < startIndex and nums[i]==nums[i-1]:
continue
path.append(nums[i])
backtracking(nums, i+1)
path.pop()
backtracking(nums, 0)
return res
题目:给你一个整数数组 nums ,找出并返回所有该数组中
不同的递增子序列,递增子序列中至少有两个元素。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
本题要求递增子序列,所以不能对数组排序,否则就破坏了原数组的顺序。
⭐️本题有一个坑:只要求递增子序列,而不要求连续递增子序列。
nums = [4, 7, 6, 7],那么[4, 7, 7]是一个所求集合。它的值与当前path中的最后一个元素值的大小关系:if path and nums[i] < path[-1]: continueif nums[i] < nums[i-1]: continue # 如果当前元素比前一个元素小,那就结束对这个元素的操作。【这个比较是不对的,会导致直接在6就continue了,导致集合[4, 7, 7],没办法统计】剪枝优化操作:
usage_list = set(),if nums[i] in usage_list: continuenums = [4, 4, 5],以索引为0的元素4为首部的集合有:[4, 4], [4, 4, 5], [4, 5]。因此在遍历到 索引为1的元素4 时,直接continue,因为此时以它为首部的集合[4, 5]已经出现过了,没必要再统计。if len(path) >= 2: res.append(path) # 只会添加长度大于等于2的集合startIndex作为每次回溯的起始点。if path not in res: res.append(path)class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
def backtracking(nums, startIndex):
if path not in res and len(path)>=2:
res.append(path[:])
# 单层回溯逻辑
for i in range(startIndex, len(nums)):
# 判断是否是递增的
if path and nums[i] < path[-1]:
continue
path.append(nums[i]) # 读取当前元素
backtracking(nums, i+1) # 回溯
path.pop()
backtracking(nums, 0)
return res
增加一个对集合头部元素是否出现过的判断
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
def backtracking(nums, startIndex):
if path not in res and len(path)>=2:
res.append(path[:])
# 单层回溯逻辑
usage_list = set()
for i in range(startIndex, len(nums)):
# 判断是否是递增的
if path and nums[i] < path[-1] or nums[i] in usage_list:
continue
usage_list.add(nums[i])
path.append(nums[i]) # 读取当前元素
backtracking(nums, i+1) # 回溯
path.pop()
backtracking(nums, 0)
return res