1.Subsets
Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: nums = [1,2,3] Output: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
给定一个集合,返回所有可能的子集集合。
rr=[] 保存最终所有子集 r=[]用来迭代所有取值情况
从子集的元素位数考虑,
当元素个数为0时,直接加入[]即可
当元素个数为1时,r取值有1,2,3 分别加入rr中,当r=[1]时,可以继续递归迭代,考虑再次基础上元素数为2的取值情况,直到所有元素已经使用完毕,此时r应该回退回上一次状态继续回溯。
初始时代码:
def subsets(nums=[1,2,3]):
rr=[]
rr.append([])
r=[]
backsubsets(rr, r, 0, nums)
#print(rr)
return rr
def backsubsets(rr, r, index, nums):
if index>len(nums)-1:
return
for i in range(index, len(nums)):
r.append(nums[i])
print('r',r)
rr.append(r)
print('rr', rr)
backsubsets(rr, r, i+1, nums)
r.pop(-1)
#rr.pop(-1)
发现最终结果不对,打印一下:
感觉后一次修改的同时修改了前一次,可能是深拷贝的问题
rr.append(r)只是在rr中保存了r的指针 如果后序r发生变化则rr中元素也会发生变化,此处应该使用深拷贝: r.copy()
def subsets(nums=[1,2,3]):
rr=[]
rr.append([])
r=[]
backsubsets(rr, r, 0, nums)
#print(rr)
return rr
def backsubsets(rr, r, index, nums):
if index>len(nums)-1:
return
for i in range(index, len(nums)):
r.append(nums[i])
print('r',r)
rr.append(r.copy())
print('rr', rr)
backsubsets(rr, r, i+1, nums)
r.pop(-1)
#rr.pop(-1)
同时这是一个组合问题,可以使用二进制算法来实现
给定数组nums=[1,2,3]其组合数有pow(2,3)=8种情况,分别对应000--111 其中1表示对应数组位置取值 0表示不取,从000变化到111即可以变化所有情况,例如110 则表示23 111则表示123
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int N = nums.length;
if (N == 0)
return new ArrayList();
List<List<Integer>> res = new ArrayList();
long numOfCombination = (long) Math.pow(2, N);
for (int i = 0; i < numOfCombination; i++) {
List<Integer> l = new ArrayList();
for (int j = 0; j < N; j++) {
if ((i&(1 << j)) > 0)
l.add(nums[j]);
}
res.add(l);
}
return res;
}
}
大神的写法:
def subsets(self, nums):
return [list(j) for i in range(len(nums)+1) for j in combinations(nums,i)]
标准回溯法:
一个用来保存所有状态 一个用来遍历所有情况取值
直接保存当前状态,
在当前状态之上考虑下一种状态,
递归下一种状态
回溯回到当前状态,进行当前状态的下一种取值可能
class Solution:
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
rr=[]
nums.sort()
self.backsubsets(rr, [], 0, nums)
return rr
def backsubsets(self, rr, r, index, nums):
rr.append(r.copy())
for i in range(index, len(nums)):
r.append(nums[i])
self.backsubsets(rr, r, i+1, nums)
r.pop(-1)
2.Subsets2
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: [1,2,2] Output: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
给出去重的组合子集
class Solution:
def subsetsWithDup(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
rr=[]
nums.sort()
self.backtrack(rr, [], 0, nums)
return rr
def backtrack(self, rr, r, index, nums):
rr.append(r.copy())
for i in range(index, len(nums)):
if i>index and nums[i]==nums[i-1]:
continue
r.append(nums[i])
self.backtrack(rr, r, i+1, nums)
r.pop(-1)
考虑nums=[1,2,2]
依次递归的顺序为[] 1 12 122 12 2 22 3
考虑重复元素 0-----index---i-----len
index用来标识当前是数组第几位 i用来在index基础上继续添加一位的可能情况,重复出现的情况是 在index基础上考虑下一位时
i=index index+1 index+2 ....当nums[i]值有重复时,会出现重复情况,因此应该去重
if i>index and nums[i]==nums[i-1]:
continue
如果遍历i时出现nums[i-1]==nums[i]时,直接跳过进行下一次循环,这有点类型与三元素去重求和等于0:
def threeSum(nums=[-2,0,0,2,2]):
nums.sort()
#print(nums)
rr = []
for k in range(len(nums)-1):
if k>=1 and nums[k-1]==nums[k]:
continue
i = k+1
j = len(nums)-1
while i<j:
#print(k, i, j)
sum = nums[k] + nums[i] + nums[j]
if sum==0:
rr.append([nums[k], nums[i], nums[j]])
while i<j and nums[i+1]==nums[i]:
i += 1
while i<j and nums[j-1]==nums[i]:
j -= 1
i += 1
j -= 1
elif sum<0:
i += 1
else:
j -= 1
return rr