LC 77. Combinations 回溯 / 改进 求组合数C(n, k)

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

第一眼就感觉非常眼熟,这题和Permutation系列非常相似,都可以用回溯的方法来做。之前求Permutation已经写过总结了,当时递归函数用引用传递传当前得到的排列cur,难点是必须考虑在下一次循环开始前怎么处理cur从而不影响之后的排列可能,当时在myPermutation调用完之后还需再次swap。这道题也一样,用同一个cur在结束后只需要将刚刚加入的 i 给取出来即可。代码:
void myCombine(vector<vector<int>>& res, vector<int>& cur, int pos, int k, int n) {
    if (k == 0) {
        res.push_back(cur);
        return;
    }
    for (int i = pos; i <= n; i++) {
        cur.push_back(i);
        myCombine(res, cur, i + 1, k - 1, n);
        cur.pop_back();
    }
}
vector<vector<int>> combine(int n, int k) {
    vector<vector<int>> res;
    vector<int> cur;
    myCombine(res, cur, 1, k, n);
    return res;
}

测试了一下,用值传递的方式大概只超过了20%,处于最差的一批,用引用传递就可以达到80%,可见效率提升还是很高的。

另外,如果觉得push_back和pop_back的成本太大的话,可以实现声明一个长度为 k 的数组,之后直接通过在指定下标位置赋值即可,代码

void myCombine(vector<vector<int>>& res, vector<int>& cur, int pos, int count, int k, int n) {
    if (k == 0) {
        res.push_back(cur);
        return;
    }
    for (int i = pos; i <= n; i++) {
        cur[count] = i;
        myCombine(res, cur, i + 1, count + 1, k - 1, n);
    }
}
vector<vector<int>> combine(int n, int k) {
    vector<vector<int>> res;
    vector<int> cur(k, 0);
    myCombine(res, cur, 1, 0, k, n);
    return res;
}
网上还有迭代的写法:
vector<vector<int>> combine(int n, int k) {
		vector<vector<int>> result;
		int i = 0;
		vector<int> p(k, 0);
		while (i >= 0) {
			p[i]++;
			if (p[i] > n) --i;
			else if (i == k - 1) result.push_back(p);
			else {
			    ++i;
			    p[i] = p[i - 1];
			}
		}
		return result;
	}

以C(4,2)为例,代码得到的 p 为:

Incremented element at index 0
[1, 0]
Moved index to the right, and copied the value from the left
[1, 1]
Incremented element at index 1
[1, 2]
Combination found!
Added [1, 2] as an answer!
Incremented element at index 1
[1, 3]
Combination found!
Added [1, 3] as an answer!
Incremented element at index 1
[1, 4]
Combination found!
Added [1, 4] as an answer!
Incremented element at index 1
[1, 5]
n exceeded at 1, moving index to the left
Incremented element at index 0
[2, 5]
Moved index to the right, and copied the value from the left
[2, 2]
Incremented element at index 1
[2, 3]
Combination found!
Added [2, 3] as an answer!
Incremented element at index 1
[2, 4]
Combination found!
Added [2, 4] as an answer!
Incremented element at index 1
[2, 5]
n exceeded at 1, moving index to the left
Incremented element at index 0
[3, 5]
Moved index to the right, and copied the value from the left
[3, 3]
Incremented element at index 1
[3, 4]
Combination found!
Added [3, 4] as an answer!
Incremented element at index 1
[3, 5]
n exceeded at 1, moving index to the left
Incremented element at index 0
[4, 5]
Moved index to the right, and copied the value from the left
[4, 4]
Incremented element at index 1
[4, 5]
n exceeded at 1, moving index to the left
Incremented element at index 0
[5, 5]
n exceeded at 0, moving index to the left
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
不得不说真的是太机智了,学不来学不来。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值