60. Permutation Sequence\78. Subsets\77. Combinations

本文探讨了排列组合中常见的几种问题,包括排列序列、子集生成及组合选取的算法实现。通过递归、回溯及数学公式等方法,详细介绍了如何高效解决这些问题,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

60. Permutation Sequence

题目描述

The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

"123"
"132"
"213"
"231"
"312"
"321"

Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.

代码实现

法一:使用递归计算这道题目。然后会发生超时。

class Solution {
public:
    bool isSatisRule(string tmp) {
        char cnt[10] = {0};
        int tlen = tmp.size();
        for(int i = 0; i < tlen; i++) {
            cnt[tmp[i]-'0']++;
            if(cnt[tmp[i]-'0'] > 1) return false;
        }

        return true;
    }

    void permutation(string &str, string tmp, int n, int stt, int k, int &num) {
        if(n == stt) {
            num++;
            if(num == k)
                str = tmp;
            return;
        }

        for(int i = 1; i <= n; i++) {
            if(num >= k) break;
            string t = tmp;
            if(isSatisRule(tmp+char(i+'0'))) 
                permutation(str, tmp+char(i+'0'), n, stt+1, k, num);
        }
    }

    string getPermutation(int n, int k) {
        string st;
        string tmp = "";
        int num = 0;
        permutation(st, tmp, n, 0, k, num);

        return st;
    }
};

法二:使用回溯。然后又超时了。

class Solution {
public:
    bool isSatisRule(string tmp) {
        char cnt[10] = {0};
        int tlen = tmp.size();
        for(int i = 0; i < tlen; i++) {
            cnt[tmp[i]-'0']++;
            if(cnt[tmp[i]-'0'] > 1) return false;
        }

        return true;
    }

    void permutation(string &str, string &tmp, int n, int stt, int k, int &num) {
        if(n == stt) {
            num++;
            if(num == k)
                str = tmp;
            return;
        }

        for(int i = 1; i <= n; i++) {
            if(num >= k) break;
            string t = tmp;
            tmp += char(i+'0');
            if(isSatisRule(tmp)) 
                permutation(str, tmp, n, stt+1, k, num);
            tmp = t;
        }
    }

    string getPermutation(int n, int k) {
        string st;
        string tmp = "";
        int num = 0;
        permutation(st, tmp, n, 0, k, num);

        return st;
    }
};

法三:既然这些方法不能用,这种情况下使用公式就可以了。

class Solution {
public:
    string getPermutation(int n, int k) {
        string ans = "";
        int i, j, t, sum, jie;
        jie = 1;
        for (i = 1; i <= n; i++){
            jie = i * jie;
            ans += to_string(i);
        }
        for (i = 0; i < n; i++){
            jie /= n - i;
            for (sum = 0, j = 1; j <= n; j++){
                if (sum + jie >= k) break;
                sum += jie;
                swap(ans[i], ans[i + j]);
            }
            k -= sum;
        }
        return ans;
    }
};
class Solution {
public:
    string getPermutation(int n, int k) {
        int pTable[10] = {1};
        for(int i = 1; i <= 9; i++)
            pTable[i] = i * pTable[i - 1];
        string result;
        vector<char> numSet;
        numSet.push_back('1');
        numSet.push_back('2');
        numSet.push_back('3');
        numSet.push_back('4');
        numSet.push_back('5');
        numSet.push_back('6');
        numSet.push_back('7');
        numSet.push_back('8');
        numSet.push_back('9');
        while(n > 0){
            int temp = (k - 1) / pTable[n - 1];
            result += numSet[temp];
            numSet.erase(numSet.begin() + temp);
            k = k - temp * pTable[n - 1];
            n--;
        }
        return result;
    }
};

78. Subsets

题目描述

这一题是非常典型的回溯类型的题目,就是找到一个字符串的所有的子集。

Given a set of distinct integers, nums, return all possible subsets.

Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:

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

代码实现

class Solution {
public:

    bool isNotInVet(vector<int> tmp, int tar) {
        int len = tmp.size();
        for(int i = 0; i < len; i++) 
            if(tmp[i] == tar) return false;
        return true;
    }

    void bptracking(vector<vector<int> > &res, int nlen, int stt, vector<int> &tmp, vector<int>& nums) {
        if(!tmp.empty() || stt == nlen) 
            res.push_back(tmp);
        if(stt == nlen)
            return;

        for(int i = stt; i < nlen; i++) {
            // 因为每个集合里的元素都是不一样的,如果遇到集合里有一样的元素的话,使用这个就很方便
            if(isNotInVet(tmp, nums[i])) { 
                tmp.push_back(nums[i]); 
                bptracking(res, nlen, i + 1, tmp, nums);
                tmp.pop_back();
            }  
        } 
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        sort(nums.begin(), nums.end() );
        int nlen = nums.size();
        vector<vector<int> > res;
        vector<int> tmp;
        res.push_back(tmp);
        bptracking(res, nlen, 0, tmp, nums);
        return res;
    }
};

77. 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],
]

代码实现

class Solution {
public:
    void combination(vector<vector<int>> &res, int n, int k, int stt, vector<int> &tmp) {
        if(tmp.size() == k) {
            res.push_back(tmp);
            return;
        }    
        if(stt == n+1) return;

        for(int i = stt; i <= n; i++) {
            tmp.push_back(i);
            combination(res, n, k, i+1, tmp);
            tmp.pop_back();
        }   
    }

    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> res;
        vector<int> tmp;
        combination(res, n, k, 1, tmp);
        return res;
    }
};

当然直接用递归的话,可以更快一些:这个思路也比较好理解。

class Solution {
public:
    vector<vector<int> > combine(int n, int k) {
        vector<vector<int> > rslt;
        vector<int> path(k, 0);
        combine(n, k, rslt, path);
        return rslt;
    }

private:
    void combine(int n, int k, vector<vector<int> > &rslt, vector<int> &path) {
        if (k == 0) {
            rslt.push_back(path);
            return;
        }
        for (int i = n; i >= 1; i--) {
            path[k - 1] = i;
            combine(i - 1, k - 1, rslt, path);
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值