给定0-9的整数,在用完一些整数之前,我能写出的最后一个数字是多少?

时间:2014-09-09 18:23:07

标签: java algorithm numbers dynamic-programming

正如标题所说,给定0-9整数的存量,在我用完一些整数之前,我能写出的最后一个数字是什么?

所以,如果我给出了一个股票,比如从0到9的每个数字为10,那么在我用完一些数字之前,我可以写的最后一个数字是多少。例如,股票为2我可以写数字1 ... 10:

1 2 3 4 5 6 7 8 9 10

此时我的股票为0,我不能写11。 另请注意,如果我获得了3的股票,我仍然只能写出1到10的数字,因为11将花费我2个,这将使我的股票为-1。

到目前为止我已经提出了什么:

public class Numbers {

public static int numbers(int stock) {
    int[] t = new int[10];
    for (int k = 1; ; k++) {

        int x = k;
        while (x > 0) {

            if (t[x % 10] == stock) return k-1;
            t[x % 10]++;
            x /= 10;

        }

    }
}

public static void main(String[] args) {
    System.out.println(numbers(4));

}

}

有了这个,我可以得到相当大的股票大小的正确答案。库存大小为10 ^ 6时,代码在~2秒内完成,并且库存为10 ^ 7个数字需要整整27秒。这还不够好,因为我正在寻找一种能够处理大到10 ^ 16的库存大小的解决方案,所以我可能需要一个O(log(n))解决方案。

这是一个像作业一样的作业,所以我没有在没有与这种泡菜搏斗的情况下来这里很长一段时间。我没有通过谷歌搜索得到任何类似的东西,而且wolfram alpha也没有认识到这种模式。

到目前为止,我所得出的结论是,总会先消失。我没有证据,但确实如此。

任何人都可以提出任何建议吗?非常感谢。


编辑:

我已经提出并实现了一种有效的方法来查找数字1 ... n的成本,这要归功于btilly的指针(请参阅下面的帖子和评论。也标记为解决方案)。在我实施二进制搜索以找到你今天晚些时候可以用给定股票编写的最后一个数字之后,我将进一步阐述这一点。


编辑2:解决方案

我完全忘记了这篇文章,所以我很抱歉没有在我的解决方案中进行编辑。不过,我不会复制实际的实现。

我找到数字费用的代码如下:

首先,让我们选择一个数字,例如9999.现在我们将通过总计每个数十位的成本来得到成本:

9 9 9 9
^ ^ ^ ^
^ ^ ^ roof(9999 / 10^1) * 10^0 = 1000
^ ^ roof(9999 / 10^2) * 10^1 = 1000
^ roof(9999 / 10^3) * 10^2 = 1000
roof(9999 / 10^4) * 10^3 = 1000

因此9999的成本是4000。

256:

2 5 6
^ ^ ^
^ ^ roof(256 / 10^1) * 10^0 = 26
^ roof(256 / 10^2) * 10^1 = 30
roof(256 / 10^3) * 10^2 = 100

因此256的成本是156。

实现这个想法会使程序只能使用没有数字1或0的数字,这就是需要进一步逻辑的原因。让我们调用上面解释的方法 C(n,d) ,其中 n 是数字我们为此获得了成本,而 d 是来自 n <的 d &#39; / em> 我们目前正在与之合作。我们还要定义一个方法 D(n,d) ,它将从 d &#39; > 名词的即可。然后我们将应用以下逻辑:

sum = C(n, d)

if D(n, d) is 1:
    for each k < d, k >= 0 :
        sum -= ( 9 - D(n, k) ) * 10^(k-1);

else if D(n, d) is 0:
    sum -= 10^(d-1)

有了这个,程序将有效地计算数字的正确成本。在此之后,我们只需应用二元搜索来找到具有正确成本的数字。

2 个答案:

答案 0 :(得分:2)

步骤1.编写一个有效的函数来计算需要使用多少股票来编写最多N的所有数字。 (提示:使用公式计算用于写出最后一位数字的所有内容,然后使用递归计算其他数字中使用的所有内容。)

步骤2.进行二元搜索以找到您可以用库存量编写的最后一个数字。

答案 1 :(得分:0)

我们可以直接计算答案。递归公式可以确定从1到10次幂减1的数字需要多少库存:

f(n, power, target){
  if (power == target)
    return 10 * n + power;
  else
    return f(10 * n + power, power * 10, target);
}

f(0,1,1) = 1 // a stock of 1 is needed for the numbers from 1 to 9
f(0,1,10) = 20 // a stock of 20 is needed for the numbers from 1 to 99
f(0,1,100) = 300 // a stock of 300 is needed for the numbers from 1 to 999
f(0,1,1000) = 4000 // a stock of 4000 is needed for the numbers from 1 to 9999

当它变得复杂时,考虑到当我们的计算在任何上述系数的第一个倍数之后着陆时所需的额外1;例如,在10(11-19)的第二个倍数上,我们需要为每个数字额外添加1

JavaScript代码:

function f(stock){
  var cs = [0];
  var p = 1;
  function makeCoefficients(n,i){
    n  = 10*n + p;
    if (n > stock){
      return;
    } else {
      cs.push(n);
      p *= 10;
      makeCoefficients(n,i*10);
    }
  }

  makeCoefficients(0,1);
  var result = -1;
  var numSndMul = 0;
  var c;

  while (stock > 0){
    if (cs.length == 0){
      return result;
    }
    c = cs.pop();
    var mul = c + p * numSndMul;

    if (stock >= mul){
      stock -= mul;
      result += p;
      numSndMul++;
      if (stock == 0){
        return result;
      }
    }

    var sndMul = c + p * numSndMul;

    if (stock >= sndMul){
      stock -= sndMul;
      result += p;
      numSndMul--;
      if (stock == 0){
        return result;
      }
      var numMul = Math.floor(stock / mul);
      stock -= numMul * mul;
      result += numMul * p;
    }
    p = Math.floor(p/10);
  }
  return result;
}

输出:

console.log(f(600));
1180

console.log(f(17654321));
16031415

console.log(f(2147483647));
1633388154