k组合生成问题-非递归

本文探讨了k组合生成问题,从游戏中的宝石选择举例,分析了字典序生成k组合的特性。通过每次迭代给最低位加1并判断是否进位,实现了非递归算法。给出了C++实现,并指出全排列和k组合问题可以利用相邻字典序规律求解。

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

k组合生成问题,是一种非常常见的问题。例如,我们在玩游戏当中,需要从 n 种宝石当中选择 k 种不同的宝石佩戴,这就是一个 k 组合的生成问题。

当 n = 6,k = 4时,按照字典序生成的 k 组合如下:

1 2 3 4 

1 2 3 5

1 2 3 6

1 2 4 5

...

3 4 5 6


1.分析

看第一个 k 组合,是以 1 开始的一个序列,包含了 1 到 n 中最小的 k 个数;而最后一个 k 组合则以 3 开头,包含了 1 到 n 中最大的 k 个数。

每个位置上,都有允许的最大值。分别是最后一个 k 组合中对应位指定的值。

利用以上特征,每次求下一个 k 组合时,可以给“最低位” + 1,根据是否达到最大值决定是否进位。

以1 2 3 6 为例,给“最低位”6 加 1,但最低位已达到最大值,需要进位。于是给3加上1,变成 1 2 4 6。而以1 2 4开头的组合,第一个是 1 2 4 5.

以1 2 5 6为例,给“最低位” 6 加 1 ,最终进位到 2 ,变成 1 3 5 6。而以1 3 开头的组合,第一个是1 3 4 5。


2.算法

写成C++代码如下:

    vector<vector<int>> combine(int n, int k) 
    {
        vector<vector<int>> ret{};
        if(n < 0 || k < 0 || k > n)
            return ret;
        
        //c[0],c[1],...,c[k-1]
        //max of c[i] == n - k + 1 + i
        //eg. max of c[k-1] == n
        
        //初始化
        vector<int> comb;
        for(size_t i = 0;i < k;++i)
            comb.push_back(i + 1);
        ret.push_back(comb);
        
        bool cf;
        while( comb[0] != (n - k + 1) )
        {
            cf = false;
            for(int j = k - 1;j >= 0;--j)
            {
                int max_val = n - k + 1 + j;
                if(comb[j] == max_val)
                    cf = true;
                else if(comb[j] < max_val)
                {
                    ++comb[j];
                    
                    if(cf)
                    {
                        for(int fw = j + 1;fw < k;++fw)
                            comb[fw] = comb[fw - 1] + 1; 
                        cf = false;
                    }                  
                    ret.push_back(comb);
                    break;
                }
            }
        }
这也是leetcode上的题,目前运行时间虽然不是最快,但是排在93.68%。排名第一的依然是递归算法。下一篇决定研究全排列和k组合生成的递归解法。


3.总结

       全排列和k组合问题,都可以利用相邻字典序之间的规律,根据当前序列求解下一个序列。把这些规律写成算法,也就解决了这些问题。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值