Algorithm 多少次;2“;发生在从0到n的所有数字中

Algorithm 多少次;2“;发生在从0到n的所有数字中,algorithm,math,language-agnostic,Algorithm,Math,Language Agnostic,查找从0到n的所有数字中“2”出现的次数 示例:n=112answer=22 numbers : 2 , 12 , 20-29 , 32 ... 92 , 102 , 112 我想出了以下方法: 设k=n的位数 f(k)=从0到10^k-1的两个数 f(1)=1//2 f(2)=10*f(1)+10^(2-1)//12,20-29,32。。。92 f(3)=10*f(2)+10^(3-1) 等等 twos(int n,int k) { 如果(n3*(低于100)+100+twos(12

查找从0到n的所有数字中“2”出现的次数

示例:
n
=112
answer
=22

numbers : 2 , 12 , 20-29 , 32 ...  92 , 102 ,  112  
我想出了以下方法:

k
=n的位数

f(k)
=从
0
10^k-1的两个数

f(1)=1//2
f(2)=10*f(1)+10^(2-1)//12,20-29,32。。。92
f(3)=10*f(2)+10^(3-1)
等等

twos(int n,int k)
{
如果(n3*(低于100)+100+twos(12)
其他的
返回msb*(f(k))+Two(余数)
}  
我的方法正确吗?
如果是,有没有比这更快的解决方案

编辑
对于这些测试用例,我的方法似乎是正确的,即模拟
结果

第1栏:n,第2栏:暴力,第3栏:我的方法

2.11
511
91 19 19
868277277
778333593359
55576 32718 32718
293911 242093 242093
10179297 7091858 7091858
59939789 51975959 51975959

f(k)
为数字2的出现次数,从0到
10^k-1
(即最多为k位数字)。 请注意,当数字从k-1增加到k时,每一个新的前导数字都有f(k-1)出现,加上前导数字本身的10^(k-1)出现:

f(k) = 10*f(k-1) + 10^(k-1)
(这正是你的公式)

解决此重复问题可提供:

f(k) = k * 10^(k-1)
例如:

f(1) = 1
f(2) = 20
f(3) = 300
f(4) = 4000
...
实际上有一种不同的方法得到这个公式。考虑所有的k个数字(其中丢失的数字被零替换)。数字的数量是10^k,每个数字中有k个数字,因此我们总共有
k*10^k
个数字。现在,每个可能的数字出现的次数相同,即
k*10^k/10=k*10^(k-1)

--编辑--

以下Java解决方案使用了上述公式,并解决了任意n in O(logn)时间的问题:


假设数字由数字组成。我们想看看所有数字的正确性,你用哑循环检查了吗?循环给出运行时错误,n=10^7,这里n可以一直到10^18。你总是可以将解决方案的结果与蛮力实现的结果进行比较。它不能在heory证明你的解决方案对每一个输入都是正确的,但它可以给你一些信心…@aseem:这个想法是用小数字来测试它…例如:它对所有的结果都正确吗?只要你坚持基数2,答案对所有的n都是精确的0;p这大部分我是正确的,但当n不是的幂时失败10@aseem:当然失败了,因为f(k)定义为计算0..10^k-1范围内的事件。你必须做额外的工作来处理任何数字。好吧,这就是任务。我不知道这是如何回答这个问题的。@KarolyHorvath:我不确定我是否理解。OP问他的方法是否正确,以及如何提高计算效率。我回答了这两个问题,我想k、 在某些情况下给出了错误的答案。顺便说一句,谢谢你的解释。
f(1) = 1
f(2) = 20
f(3) = 300
f(4) = 4000
...
// Counts occurrences of digit 2 in numbers less than n
public static int count(int n) {
  int count = 0;
  int factor = 1;
  int pos = 0;
  while (true) {
    int m = n / factor;
    if (m == 0) //Past last digit
      break;
    int d = m % 10;      

    count += d * pos * factor / 10; 

    if (d == 2)
      count += n % factor;
    else if (d > 2) {
      count += factor; 
    }

    factor = 10 * factor;
    pos++;
  }

  return count;
}  
f1(n) = (n+8) / 10
f1(1) = 0
f1(2) = 1
f1(12) = 2
f1(21) = 2
f1(22) = 3 
f2(n) = 10 * f1(n/10)  # almost right
f2(10) = 0
f2(20) = 10 * f1(2) = 10  # wrong
f2(25) = 10 * f1(2) = 10  # wrong
f2(29) = 10 * f1(2) = 10  
f2(30) = 10 * f1(3) = 10
f2(n) = 10*f1(n/10) - 9 + n1 # if n2==2
f2(n) = 10*f1(n/10) - 9 + n%10 # if n2==2
f3(n) = 100*f1(n/100) # if n3 != 2
f3(n) = 100*f1(n/100) - 99 + n%100 # if n3 == 2
f(n) = f1(n) + f2(n) + f3(n) + ...
public static int count2(int n) {
    int res = (n+8) / 10;
    int divider = 10;
    while (n>= 2*divider){
        int na = n / divider;
        res = res + divider * ((na+8) /10);
        if (na%10==2)
             res = res - divider + 1 + n % divider;
        divider = divider * 10;
    }
    return res;
}