对于给定的整数 a,找到总和为 a 的所有唯一的正整数组合

2024-02-16

不是家庭作业问题。 我正在回答这些问题here http://www.careercup.com/question?id=5653595164770304我遇到了这个问题。 有人已经回答了。我已经尝试了很多方法来理解所使用的递归,但我无法理解它。有人可以向我解释一下吗?

编写一个函数,对于给定的数字,通过使用加法和任何等于或小于该数字且大于零的数字,打印出生成该数字的所有不同方法。

例如,给定a = 5,我们有以下七种方式来凑成5:

  • 1, 1, 1, 1, 1
  • 1, 4
  • 1, 1, 1, 2
  • 1, 1, 3
  • 2, 3
  • 1, 2, 2
  • 5

该网站的解决方案是用 C++ 编写的:

void printSeq( int num , int a[] , int len , int s )
{
    if( num <= 0 )
    {
        for( int j = 0 ; j < len ; j++ )
            cout << a[ j ] << "," ;
        cout << endl;

        return;
    }

    for(int i = s ; i <= num ; i++)
    {
        a[ len ] = i;
        printSeq( num - i , a , len + 1 , i );
    }
}

int main()
{
    int a[5];
    printSeq(5,a,0,1);
    cin.get();
    return 0;
} 

当遇到这样的问题时,最好从编辑器/IDE 中退后一步,在白板上画出一个简单的案例来思考问题。甚至还不需要编写伪代码,只需绘制一个简单案例(例如a = 3)因为这个问题会一直龟缩下去。另外,一开始不要担心重复的组合。尝试找到一个能够提供所有所需组合的解决方案,然后改进您的解决方案,以免出现重复的情况。在这种情况下,为什么不看看可管理的情况a = 3?让我为你画一张小图。绿色复选标记表示我们已得到有效的组合,红色十字表示组合无效。

正如您所看到的,我们从三个空子组合开始,然后通过向每个子组合附加一个数字来构建三个新的子组合。我们想要检查所有可能的路径,因此我们选择 1、2 和 3,最终得到[1], [2] and [3]。如果组合中的数字之和等于 3,我们就找到了一个有效的组合,因此我们可以停下来检查这条路径。如果组合中的数字之和超过3,则该组合无效,我们也可以停止。如果不是这种情况,我们只需继续构建组合,直到得出有效或无效的解决方案。

由于您的问题似乎主要是关于如何针对此类问题制定递归解决方案,而不是关于具体语法,并且您恰好找到了一个 C++ 解决方案,因此我将在 Python 中提供一个解决方案(它几乎看起来像伪代码)这就是它所知道的)。

def getcombs(a, combo = None):
    # initialize combo on first call of the function
    if combo == None:
        combo = []

    combosum = sum(combo) # sum of numbers in the combo, note that sum([]) == 0
    # simple case: we have a valid combination of numbers, i.e. combosum == a
    if combosum == a:
        yield combo # this simply gives us that combination, no recursion here!
    # recursive case: the combination of numbers does not sum to a (yet)
    else:
        for number in range(1, a + 1): # try each number from 1 to a               
            if combosum + number <= a:  # only proceed if we don't exceed a
                extcombo = combo + [number] # append the number to the combo
                # give me all valid combinations c that can be built from extcombo
                for c in getcombs(a, extcombo):
                    yield c

让我们测试一下代码吧!

>>> combos = getcombs(3)
>>> for combo in combos: print(combo)
... 
[1, 1, 1]
[1, 2]
[2, 1]
[3]

这似乎工作正常,另一个测试a = 5:

>>> combos = getcombs(5)
>>> for combo in combos: print(combo)
... 
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]

该解决方案包括我们正在寻找的所有七种组合,但代码仍然会产生重复项。您可能已经注意到,不必采用比先前选择的数字更小的数字来生成所有组合。因此,让我们添加一些仅开始构建的代码extcombo对于不小于组合中当前最后一个数字的数字。如果组合为空,我们只需将前一个数字设置为 1。

def getcombs(a, combo = None):
    # initialize combo on first call of the function
    if combo == None:
        combo = []

    combosum = sum(combo) # sum of numbers in combo, note that sum([]) == 0
    # simple case: we have a valid combination of numbers, i.e. combosum == a
    if combosum == a:
        yield combo # this simply gives us that combination, no recursion here!
    # recursive case: the combination of numbers does not sum to a (yet)
    else:
        lastnumber = combo[-1] if combo else 1 # last number appended
        for number in range(lastnumber, a + 1): # try each number between lastnumber and a
            if combosum + number <= a:
                extcombo = combo + [number] # append the number to the combo
                # give me all valid combinations that can be built from extcombo
                for c in getcombs(a, extcombo):
                    yield c

再次,让我们测试一下代码!

>>> combo = getcombs(5)
>>> for combo in combos: print(combo)
... 
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 4]
[2, 3]
[5]

所提出的解决方案可能不是现有的最有效的解决方案,但希望它能鼓励您递归地思考。一步步分解问题,用少量的投入画出一个简单的案例,一次解决一个问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对于给定的整数 a,找到总和为 a 的所有唯一的正整数组合 的相关文章

随机推荐