C++實(shí)現(xiàn)LeetCode(77.Combinations 組合項(xiàng))
[LeetCode] 77.Combinations 組合項(xiàng)
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],
]
這道題讓求1到n共n個(gè)數(shù)字里k個(gè)數(shù)的組合數(shù)的所有情況,還是要用深度優(yōu)先搜索DFS來解,根據(jù)以往的經(jīng)驗(yàn),像這種要求出所有結(jié)果的集合,一般都是用DFS調(diào)用遞歸來解。那么我們建立一個(gè)保存最終結(jié)果的大集合res,還要定義一個(gè)保存每一個(gè)組合的小集合out,每次放一個(gè)數(shù)到out里,如果out里數(shù)個(gè)數(shù)到了k個(gè),則把out保存到最終結(jié)果中,否則在下一層中繼續(xù)調(diào)用遞歸??蓪懗龃a如下:
解法一:
class Solution { public: vector<vector<int>> combine(int n, int k) { vector<vector<int>> res; vector<int> out; helper(n, k, 1, out, res); return res; } void helper(int n, int k, int level, vector<int>& out, vector<vector<int>>& res) { if (out.size() == k) {res.push_back(out); return;} for (int i = level; i <= n; ++i) { out.push_back(i); helper(n, k, i + 1, out, res); out.pop_back(); } } };
對(duì)于n = 5, k = 3, 處理的結(jié)果如下:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
我們?cè)賮砜匆环N遞歸的寫法,此解法沒用helper當(dāng)遞歸函數(shù),而是把本身就當(dāng)作了遞歸函數(shù),寫起來十分的簡(jiǎn)潔,也是非常有趣的一種解法。這個(gè)解法用到了一個(gè)重要的性質(zhì) C(n, k) = C(n-1, k-1) + C(n-1, k),這應(yīng)該在我們高中時(shí)候?qū)W排列組合的時(shí)候?qū)W過吧,博主也記不清了??傊?,翻譯一下就是,在n個(gè)數(shù)中取k個(gè)數(shù)的組合項(xiàng)個(gè)數(shù),等于在n-1個(gè)數(shù)中取k-1個(gè)數(shù)的組合項(xiàng)個(gè)數(shù)再加上在n-1個(gè)數(shù)中取k個(gè)數(shù)的組合項(xiàng)個(gè)數(shù)之和。這里博主就不證明了,因?yàn)槲乙膊粫?huì),就直接舉題目中的例子來說明吧:
C(4, 2) = C(3, 1) + C(3, 2)
我們不難寫出 C(3, 1) 的所有情況:[1], [2], [3],還有 C(3, 2) 的所有情況:[1, 2], [1, 3], [2, 3]。我們發(fā)現(xiàn)二者加起來為6,正好是 C(4, 2) 的個(gè)數(shù)之和。但是我們仔細(xì)看會(huì)發(fā)現(xiàn),C(3, 2)的所有情況包含在 C(4, 2) 之中,但是 C(3, 1) 的每種情況只有一個(gè)數(shù)字,而我們需要的結(jié)果k=2,其實(shí)很好辦,每種情況后面都加上4,于是變成了:[1, 4], [2, 4], [3, 4],加上C(3, 2) 的所有情況:[1, 2], [1, 3], [2, 3],正好就得到了 n=4, k=2 的所有情況了。參見代碼如下:
解法二:
class Solution { public: vector<vector<int>> combine(int n, int k) { if (k > n || k < 0) return {}; if (k == 0) return {{}}; vector<vector<int>> res = combine(n - 1, k - 1); for (auto &a : res) a.push_back(n); for (auto &a : combine(n - 1, k)) res.push_back(a); return res; } };
我們?cè)賮砜匆环N迭代的寫法,也是一種比較巧妙的方法。這里每次先遞增最右邊的數(shù)字,存入結(jié)果res中,當(dāng)右邊的數(shù)字超過了n,則增加其左邊的數(shù)字,然后將當(dāng)前數(shù)組賦值為左邊的數(shù)字,再逐個(gè)遞增,直到最左邊的數(shù)字也超過了n,停止循環(huán)。對(duì)于n=4, k=2時(shí),遍歷的順序如下所示:
0 0 #initialization
1 0
1 1
1 2 #push_back
1 3 #push_back
1 4 #push_back
1 5
2 5
2 2
2 3 #push_back
2 4 #push_back
...
3 4 #push_back
3 5
4 5
4 4
4 5
5 5 #stop
解法三:
class Solution { public: vector<vector<int>> combine(int n, int k) { vector<vector<int>> res; vector<int> out(k, 0); int i = 0; while (i >= 0) { ++out[i]; if (out[i] > n) --i; else if (i == k - 1) res.push_back(out); else { ++i; out[i] = out[i - 1]; } } return res; } };
到此這篇關(guān)于C++實(shí)現(xiàn)LeetCode(Combinations 組合項(xiàng))的文章就介紹到這了,更多相關(guān)C++實(shí)現(xiàn)Combinations 組合項(xiàng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++實(shí)現(xiàn)LeetCode(94.二叉樹的中序遍歷)
- C++實(shí)現(xiàn)LeetCode(112.二叉樹的路徑和)
- C++實(shí)現(xiàn)LeetCode(78.子集合)
- C++實(shí)現(xiàn)LeetCode(47.全排列之二)
- C++實(shí)現(xiàn)LeetCode(90.子集合之二)
- C++實(shí)現(xiàn)LeetCode(113.二叉樹路徑之和之二)
- C++實(shí)現(xiàn)LeetCode(39.組合之和)
- C++實(shí)現(xiàn)LeetCode(38.計(jì)數(shù)和讀法)
- C++實(shí)現(xiàn)LeetCode(51.N皇后問題)
- C++實(shí)現(xiàn)LeetCode(46.全排列)
- C++實(shí)現(xiàn)LeetCode(43.字符串相乘)
相關(guān)文章
vscode調(diào)試gstreamer源碼的詳細(xì)流程
在本文中主要介紹了如何使用vscode調(diào)試C++和python程序,并進(jìn)一步分析了如何調(diào)試gstreamer源碼,講述了如何調(diào)試gstreamer源碼的具體流程,感興趣的朋友跟隨小編一起看看吧2023-01-01