【问题标题】:Algorithm for incrementing numbers in each position in an array在数组中的每个位置递增数字的算法
【发布时间】:2013-02-13 16:33:32
【问题描述】:

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

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

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

# In Ruby

def print_all_numbers(arr_ranges)
  arr = arr_ranges.map { 0 }   # convert it to [0, 0, 0]

  while (true)
    incrementer_index = 0
    puts arr.join
    arr[incrementer_index] += 1
    while arr[incrementer_index] > arr_ranges[incrementer_index]
      arr[incrementer_index] = 0
      incrementer_index += 1
      return if incrementer_index >= arr.length 
      arr[incrementer_index] += 1
    end
  end
end

print_all_numbers([3, 6, 2])

【问题讨论】:

    标签: algorithm


    【解决方案1】:

    在我看来,递归更简单。使函数获取数字最大值列表和包含到目前为止计算的数字的后缀。如果列表为空。后缀是要打印的数字。否则,从列表中剥离最后一个最大值并迭代,递归调用自己。我不知道鲁比。这是一个(经过测试的)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 个数字(并循环遍历它的可能性),并减少数组和递归......这是有趣的技术,我通常不会这样递归……这种技术有名字吗?
    • (我认为您的解决方案需要range(0, thisDigitMaximum + 1)
    • 该技术没有特殊名称。你是对的范围。我没有仔细阅读你的问题。我已经更新了我的答案。
    【解决方案2】:

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

    十进制示例:要提取 76543 的第四位,我们使用 (76543 div 1000) mod 10。

    工作德尔福代码

    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

    【讨论】:

      【解决方案3】:

      您有特定的语言吗? 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]。现在这是我的新前缀列表,我会重复,直到我查看了所有最大值。所有这些都不需要递归。我也觉得这个解决方案在概念上和从代码上都更容易理解。

      这是一个 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(),但由于我将 strs 和 ints 组合在一起,因此我想避免任何类型错误

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-28
        • 2020-06-21
        • 2011-10-31
        • 2012-10-05
        • 1970-01-01
        • 2019-07-21
        • 1970-01-01
        相关资源
        最近更新 更多