溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++如何實現(xiàn)組合項

發(fā)布時間:2021-07-15 09:15:01 來源:億速云 閱讀:125 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“C++如何實現(xiàn)組合項”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C++如何實現(xiàn)組合項”吧!

Combinations 組合項

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個數(shù)字里k個數(shù)的組合數(shù)的所有情況,還是要用深度優(yōu)先搜索DFS來解,根據(jù)以往的經(jīng)驗,像這種要求出所有結(jié)果的集合,一般都是用DFS調(diào)用遞歸來解。那么我們建立一個保存最終結(jié)果的大集合res,還要定義一個保存每一個組合的小集合out,每次放一個數(shù)到out里,如果out里數(shù)個數(shù)到了k個,則把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();
        }
    }
};

對于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

我們再來看一種遞歸的寫法,此解法沒用helper當遞歸函數(shù),而是把本身就當作了遞歸函數(shù),寫起來十分的簡潔,也是非常有趣的一種解法。這個解法用到了一個重要的性質(zhì) C(n, k) = C(n-1, k-1) + C(n-1, k),這應(yīng)該在我們高中時候?qū)W排列組合的時候?qū)W過吧,博主也記不清了。總之,翻譯一下就是,在n個數(shù)中取k個數(shù)的組合項個數(shù),等于在n-1個數(shù)中取k-1個數(shù)的組合項個數(shù)再加上在n-1個數(shù)中取k個數(shù)的組合項個數(shù)之和。這里博主就不證明了,因為我也不會,就直接舉題目中的例子來說明吧:

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) 的個數(shù)之和。但是我們仔細看會發(fā)現(xiàn),C(3, 2)的所有情況包含在 C(4, 2) 之中,但是 C(3, 1) 的每種情況只有一個數(shù)字,而我們需要的結(jié)果k=2,其實很好辦,每種情況后面都加上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;
    }
};

我們再來看一種迭代的寫法,也是一種比較巧妙的方法。這里每次先遞增最右邊的數(shù)字,存入結(jié)果res中,當右邊的數(shù)字超過了n,則增加其左邊的數(shù)字,然后將當前數(shù)組賦值為左邊的數(shù)字,再逐個遞增,直到最左邊的數(shù)字也超過了n,停止循環(huán)。對于n=4, k=2時,遍歷的順序如下所示:

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;
    }
};

到此,相信大家對“C++如何實現(xiàn)組合項”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI