用于递增数组中每个位置的数字的算法

时间:2013-02-13 05:25:52

标签: algorithm

我想知道这个算法是否有正式的名称以及解决这个问题的优雅方法:问题是 - 给定一个数组,比如[3, 6, 2],打印出所有以{{{{1}开头的数字1}},000100200,然后下一个数字将“结转”并变为300,然后变为010。它就像汽车的里程表,除了可以增加另一端的数字。 110是第二个数字的最大数字。 6是第三位数的最大数字。因此,程序应打印出2作为最后一个数字。

我想出了下面的解决方案,但它看起来太乱了。所以我想知道是否有一个优雅的解决方案,并且这个问题和解决方案实际上有一个正式的名称和一个已知的优雅解决方案吗?

递归实际上是可能的,但我认为如果递归返回所有数字的数组,如果输入数组中有10或15个数字,算法将无法处理它,因为生成的数组可以增长它呈指数级变化,变得非常大,占用大量内存。

362

3 个答案:

答案 0 :(得分:1)

在我看来,递归更简单。使函数采用数字最大值列表和包含到目前为止计算的数字的后缀。如果列表为空。后缀是要打印的数字。否则,剥离列表中的最后一个最大值并迭代,递归调用自己。我不认识Ruby。这是一个(经过测试的)Python解决方案:

#!/usr/bin/python

def printNumbers(digitMaxima, suffix=''):
    if len(digitMaxima) == 0:
        print suffix
        return

    thisDigitMaximum = digitMaxima[-1]
    remainingDigitMaxima = digitMaxima[:-1]
    for d in range(0, thisDigitMaximum+1):
        digitAsString = '%d' % d
        printNumbers(remainingDigitMaxima, digitAsString + suffix)

printNumbers([3, 6, 2])

答案 1 :(得分:0)

有混合基(或混合基数)位置数字系统。众所周知的例子 - 小时 - 分钟 - 秒。您可以通过简单的循环遍历所有值。 预先计算基数的部分乘积,并使用整数除法和模数运算来隔离每个数字。

十进制系统示例:提取76543的第四位数字,我们使用(76543 div 1000)mod 10.

使用Delphi代码

var
  A, Products: TDynIntegerArray;
  Len, i, j: Integer;
  s: string;
begin
  A := TDynIntegerArray.Create(3, 4, 2);
  Len := Length(A);
  SetLength(Products, Len);
  Products[Len - 1] := 1;
  for i := Len - 2 downto 0  do
    Products[i] := Products[i + 1] * (A[i + 1] + 1); //partial products
  for i := 0 to Products[0] * (A[0] + 1) - 1 do begin // overall count of "numbers"
    s := '';
    for j := 0 to Len - 1 do
      s := s + IntToStr((i div Products[j]) mod (A[j] + 1));
    Memo1.Lines.Add(s); // output string
  end;

输出: 000 001 002 010 011 012 020 021 022 030 031 032 040 041 042 100 101 102 110 111 112 120 121 122 130 131 132 140 141 142 200 201 202 210 211 212 220 221 222 230 231 232 240 241 242 300 301 302 310 311 312 320 321 322 330 331 332 340 341 342

答案 2 :(得分:0)

你有特定的语言吗? Python有一个range() method,这使得像这样的问题相当简单。 range(n)会返回0n-1之间所有数字的列表,因此range(3)会返回[0, 1, 2]。一些轻量级的谷歌搜索告诉我,可以在Ruby using (0..n-1)中创建类似的效果(虽然这看起来有点像hackish)。

使用range(),然后我采用动态编程方法解决问题,我将所有可能的前缀存储在我看过的数字中(以无前缀开头)。我将遍历每个最大数字,计算所有可能的有效数字,然后将它们与有效前缀组合,得到一个新的有效前缀列表,比前一个列表长1位。一旦我的“前缀”与所需的数字一样长,我就完成了。

例如,给定[1, 2, 3],首先我生成[0, 1](所有有效数字最多为1)。接下来,我生成[0, 1, 2](所有有效数字最多为2),然后将这些数字与我的可能前缀列表([0, 1])组合以生成[00, 01, 02, 10, 11, 12]。这是我的新前缀列表,我重复一遍,直到我查看了所有的maxiumum值。所有这些都不需要递归。我也觉得这个解决方案在概念上和查看代码时都更容易理解。

这是一个Python实现:

def printNumbers(maxNums):
    possibleNums = [""] #start with empty prefix

    for digit in maxNums: #start with the first digit then work back
        possibleSuffixes = range(digit + 1) #+1 to allow us to capture the number itself

        newNums = [] #this will hold the new list of possible numbers
        for prefix in possibleNums: #looking at each prefix
            for suffix in possibleSuffixes: #looking at each suffix
                newNums.append("{}{}".format(prefix, suffix)) #join them
        possibleNums = newNums

    for num in possibleNums: #for each number
        print num

请注意,我可以使用字符串连接代替"{}{}".format(),但由于我要合并str s和int,我想避免任何类型错误