77. Combinations

Problem:

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

Example:

Input: n = 4, k = 2
Output:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

思路
这题的思路很难直接用语言表述,建议看代码,然后再纸上将其每一步运行的结果一步步写出,就好理解了。
大致的思路是这样的,它是按照从右往左来试探的。首先确定好低位之后,最高位的值如果不超过n(高位低位以数组的下标来理解)则满足条件。如果最高位的值超过n,则说明次高位的值还有增加的空间,调整次高位的值(++),再让最高位的值等于次高位的值然后依次往上递增,看是否满足条件。如果较高位的值都超过了n,则会一直往低位去寻找,如果每一位的值都超过了n,那么最好寻找的下标i会小于0,从而不满足while循环的条件,循环终止,重新开始。

Solution:

vector<vector<int>> combine(int n, int k) {
    vector<vector<int>> res;
    int i = 0;
    vector<int> p(k, 0);
        
    while (i >= 0) {
        p[i]++;
        if (p[i] > n) 
             --i;
        else if (i == k-1) 
            res.push_back(p);
        else {
            ++i;
            p[i] = p[i-1];
        }
    }
        
    return res;            
}

性能
Runtime: 76 ms  Memory Usage: 11.8 MB

扩展
有兴趣的同学可以运行下面的代码(来自于LeetCode)来理解上面代码的思路,验证流程是否正确,确实挺佩服老外的钻研精神。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

string toString(vector<int> v) {
    string ans = "[";
    for (int i: v) {
        ans += i + '0';
        ans += ", ";
    }
    ans = ans.substr(0, ans.length() - 2) + "]";
    return ans;
}

string toString(vector<vector<int>> v) {
    string ans = "[";
    for (vector<int> i: v) {
        ans += toString(i);
        ans += ", ";
    }
    ans = ans.substr(0, ans.length() - 2) + "]";
    return ans;
}

class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> ans;
        vector<int> c(k, 0); // vector of length k, all 0s
        int i = 0;
        while (i >= 0) {
            // Increment element at index i
            c[i]++;
            cout << "Incremented element at index " << i << endl;
            cout << toString(c) << endl;
            
            /* Move index to the left if the element
             * at index i has exceeded n.
             */
            if (c[i] > n) {
                i--;
                cout << "n exceeded at " << i+1 << ", moving index to the left" << endl;
            }
            
            /* If the index is at the end of the vector
             * c, then (because the other conditions are
             * obeyed), we know we have a valid combination,
             * so push it to our ans vector<vector<>>
             */
            else if (i == k - 1) {
                ans.push_back(c);
                cout << "Combination found!" << endl;
                cout << "Added " << toString(c) << " as an answer!" << endl;
            }
            
            /* Move index to the right and set the
             * element at that index equal to the
             * element at the previous index.
             * 
             * Because of the increment at the beginning
             * of this while loop, we ensure that the
             * element at this index will be at least
             * one more than its neighbor to the left.
             */
            else {
                i++;
                c[i] = c[i - 1];
                cout << "Moved index to the right, and copied the value"
                << " from the left" << endl;
                cout << toString(c) << endl;
            }
        }
        return ans;
    }
};

int main() {
    Solution sol;
    cout << toString(sol.combine(4, 2)) << endl;
    return 0;
}
相关链接如下:

知乎:littledy

欢迎关注个人微信公众号:小邓杂谈,扫描下方二维码即可

作者:littledy
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/dysjtu1995/p/12250987.html