3 计算数字k在0到n中的出现的次数,k可能是0~9的一个值
例如n=12,k=1,在 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],我们发现1出现了5次 (1, 10, 11, 12)
AC
int countDigitOne(int n, int k) {
if (n<10 &&k==0) {
return 1;
}
int sum =0;
int level = 1;
while(n / level != 0){
if (k == 0 && n / (level * 10) == 0) {// 最高位不能为0
break;
}
int cur = (n/level) %10;//计算当前位
int bef = n/(10*level);//计算当前位高位
int aft = n - n/level *level;//计算当前位的低位
if (cur >k) {
sum += (bef+1)*level;
}else if (cur <k) {
sum += (bef)*level;
}else{
sum += (bef)*level +aft+1;
}
level*= 10;
}
return sum;
}
这道算法题其实算不上难,但是我的思路却一直限制了我,走了一些弯路,实在不应该。
首先看这道算法题,计算出现的次数,我们可以看一个例子来理解这道题。
如123中出现的2的次数。
首先123中出现了多少次2,我们可以这么想,个位有多少个2,十位有多少个2,百位有多少2。
1,个位有多少2呢?因为3是大于2的,所以2 12 22 32 42…122一共有12 +1 个,我们可以想象,如果个位的3小于2,那么就只有12个了,最后一个12X上不会有。如果等于呢 则也是12+1。
2,十位有多少2呢? 因为2 ==2 ,所以 21 22 23 24 25…29 120 121 122,这里可以看出来加入十位大于2的时候,则会有 20个,如果小于2,则10个,如果等于,则是10 + 个位+1 (因为个位是2,而计数从0开始 ,如这里加的这个1是120这个)
这里我们可以进行总结:
如果 当前位大于k,则 (高位+1)乘 当前的计数级别(个位为1,十位为10,百位为百)
如果当前位小于k, 则 为高位 乘 当前的计数级别。
如果等于,则为 高位数 乘 当前计数级别 + 低位数+1。
这里的难点就只剩下怎么计算这个当前位,怎么计算当前位的高位,怎么计算当前位的低位。
例如123 ,如果要计算十位的高位,低位,当前位。
当前位:123/10(计数级别) %10(固定10) = 12%10 = 2
高位: 123/(10(固定10) * 10(计数级别))
低位: 123 - 123/10(计数级别)*10(计数级别)
整理一下就是:
int cur = (n/level) %10;//计算当前位
int bef = n/(10*level);//计算当前位高位
int aft = n - n/level *level;//计算当前位的低位