大家好,我是小魔龙,Unity3D软件工程师,VR、AR,虚拟仿真方向,不定时更新软件开发技巧,生活感悟,觉得有用记得一键三连哦。
“找出所欲偶相加之和为n的k个数的组合。”
题目链接:
来源:力扣(LeetCode)
链接: 216. 组合总和 III - 力扣(LeetCode)
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。
题意要我们找出所有相加之和为 n 的 k 个数的组合,组合中只有1-9的数字,并且每组组合不能重复。
这意味着这个组合中包含9个数字,可以将原问题转化为找出1-9中满足以下条件的集合:
这道题可以使用枚举的方式来解题,序列中有9个数,每个数有被选中和不被选中两种状态,状态的总数是29,所以可以用一个9位二进制数来记录当前所有位置的状态。
按顺序枚举[0,2p-1]中的所有整数的时候,通过位运算的方法得到对应的自己序列,然后再判断大小是否为k,以及集合中元素的和是否为n,如果满足,就返回答案。
代码参考:
class Solution {
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> combinationSum3(int k, int n) {
for (int mask = 0; mask < (1 << 9); ++mask) {
if (check(mask, k, n)) {
ans.add(new ArrayList<Integer>(temp));
}
}
return ans;
}
public boolean check(int mask, int k, int n) {
temp.clear();
for (int i = 0; i < 9; ++i) {
if (((1 << i) & mask) != 0) {
temp.add(i + 1);
}
}
if (temp.size() != k) {
return false;
}
int sum = 0;
for (int num : temp) {
sum += num;
}
return sum == n;
}
}
时间复杂度:O(M x 2M)
其中M为集合的大小,M固定为0,一共有2M个状态,每个状态需要O(M + k) = O(M)的判断(k ≤ M),总时间复杂度为O(M x 2M)。
空间复杂度:O(M)
即存放临时集合的控件代价。
代码实现的过程中,用到了位运算,那么位运算是如何得到所有数的状态的呢?
比如说,对于某一个位置上的数字i以及二进制数mark,可以判断(1 << i) & mark 是否为 0,如果不为0则说明i在子集当中。
当然,9位二进制数i的范围是[0,8],不是数字的[1,9],就需要做一个映射。