今天看到一道有趣的算法题,题目如下:
N为正整数,计算从1到N的所有整数中包含数字1的个数。比如,N=10,从1,2...10,包含有2个数字1。
相信很多人都能立刻得出以下的解法:
for(n:N)
{
判断n包含1的个数;
累加计数器;
}
这是最直接的解法,但遗憾的是,时间复杂程度为O(N*logN)。因为还需要循环判断当前的n的各位数,该判断的时间复杂程度为O(logN)。
接下来就应该思考效率更高的解法了。说实话,这道题让我想起另外一道简单的算法题:
N为正整数,计算从1到N的整数和。
很多人都采用了循环求解。然后利用初等数学知识就知道S=N*(N+1)/2,所以用O(1)的时间就可以处理。
再回到本道题目,同理应该去寻找到结果R与N之间的映射关系。
分析如下:
假设N表示为a[n]a[n-1]...a[1],其中a[i](1<=i<=n)表示N的各位数上的数字。
c[i]表示从整数1到整数a[i]...a[1]中包含数字1的个数。
x[i]表示从整数1到10^i - 1中包含数字1的个数,例如,x[1]表示从1到9的个数,结果为1;x[2]表示从1到99的个数,结果为20;
当a[1]=0时,c[1] = 0;
当a[1]=1时,c[1] = 1;
当a[1]>1时,c[1] = 1;
当a[2]=1时,c[2] = a[1] +1+ c[1] + x[1];
当a[2]>1时,c[2] = a[2]*x[1]+c[1]+10;
当a[3]=1时,c[3] = a[2]*a[1] +1+ c[2] + x[2];
当a[3]>1时,c[3] = a[3]*x[2]+c[2]+10^2;
......
以此类推
当a[i]=1时,c[i] = a[i-1]*...*a[1] +1+ c[i-1]+x[i-1];
当a[i]>1时,c[i] = a[i]x[i-1]+c[i-1]+10^(i-1);
实现的代码如下:
public static int search(int _n)
{
int N = _n/10;
int a1 = _n%10,a2;
int x = 1;
int ten = 10;
int c = a1 == 0?0:1;
while(N > 0)
{
a2 = N%10;
if(a2 == 0);
else if(a2 == 1)c = a1 + 1 + x + c;
else c = a2*x + c + ten;
a1 = 10*a1 + a2;
N /=10;
x = 10*x + ten;
ten *= 10;
}
return c;
}
而以上解法的时间复杂程度只有O(logN)
如果您路过这里,您有更好的解法吗?:)
分享到:
相关推荐
(android demo)算法实现:计算十进制数N的二进制形式中包含数字1的个数
C++计算一个数字的二进制中0或1的个数原理及代码
例如输入 12,从 1 到 12 这些整数中包含 1 的数字有 1, 10, 1 1 和 12, 1 一共出现了 5 次 代码实现(GCC编译通过): #include stdio.h #include stdlib.h int count1(int n); int count2(int n); int main...
统计1到n之间所有含1的数字个数f(n),并找出n以内最大的那个f(m)=m的值,f(n)的时间复杂度为O(logn),找最大的那个f(m)=m的值的时间复杂度为O(n)。... 判断n包含1的个数; 累加计数器; } 完全一致
例如,输入12,1~12这些整数中包含1的数字有1,10,11,12一共出现了5次。 解题思路一:直接累加1~n中每个整数中1出现的次数。 class Solution: def NumberOf1Between1AndN_Solution(self, n): # write code here...
5.6 编写程序,将一个包含有20个数据的数组M分成两个数组:正数数组P和负数数组N,并分别把这两个数组中的数据的个数显示出来。 5.7 试编制一个汇编语言程序,求出首地址为DATA的100D字数组中的最小偶数,并把它放在...
(1)对于给定的正整数集合S={w_1,w2,……,wn}和正...(3)给定一个自然数N,0\leN\le4999和M各不同的十进制数字X1,X2,……,XM, 找出由这些数字所构成的正整数中N的倍数最小的正整数,设该正整数不超过232-1。 (4)
20015当n为152时,分别求出n的个位数字(digit1)、十位数字(digit2)和百位数字(digit3)的值。 3 20026 输入2个整数 num1 和 num2,计算并输出它们的和、差、积、商与余数。 4 第3周(M3) 5 20031 求1+2+3+......+100...
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。 例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。 来源:力扣(LeetCode) 奇妙解答 以大家熟知的数字“1024”为例,...
输入的第一行是一个单个的确定的正整数T,他指名接下来的数字的个数,然后是 T 行,每一行包括一个确定的正整数N,1<=N<=1,000,000,000。 【输出说明】 对每一个数字N,产生一行输出包括一个非负整数Z(N)。 【样例...
3. 已知f(0)=f(1)=1,f(2)=0,f(n)=f(n-1)-2*f(n-2)+f(n-3)(n>2),求f(0)到f(50)中的最大值。 考试题十 1. 已知:S=2+4+8+16+32+,,求S不大于1500的最大值。 2. 已知数列:f(0)=1,f(1)=2...
1.分别求字符串中包含字母、空格、数字和其它字符的个数 2.求表达式结果 3.求素数 4.求天数 5.求一个正整数的各位数字之和 6.求最大公约数&最小公倍数 7.杨辉三角 8.兔子数列(斐波那契数列) 9.组成无重复数字的三位...
说明:输入的第1个数表示学生人数(n=9),接着输入的9个成绩中,累加和为628.5(所有小数均保留一位小数输出),平均分为69.8分;平均分以上(A档)有4人,占44.4%,平均分以下(B档)有5人,占55.6%;A档的最低...
13. 考虑如下递归算法 solve(n) if n<=1 return 1 else if n>=5 return n*solve(n-2) else return n*solve(n-1) 则调用 solve(7)得到的返回结果为( )。 答案:C. 210。递归算法 solve(n) 的返回结果为 210。 14....
输入的第一行是一个单个的确定的正整数T,他指名接下来的数字的个数,然后是T行,每一行包括一个确定的正整数N,1<=N<=1,000,000,000。 【输出说明】 对每一个数字N,产生一行输出N!计算结果,用科学记数法输出。 ...
包含近年所有C语言竞赛题目。
答案是D,解析是n个点最多n(n+1)/2条边,要不连通,至少去掉n-1条边n(n+1)/2-(n-1)≥28,n最小为8。 试题9:一些数字可以颠倒过来看,例如0、1、8颠倒过来看还是本身,6颠倒过来是9,9颠倒过来看还是6,其他数字...
1、从弹框中,分两次输入两个数字,分别保存在 a 和 b中 2、如果 a 大于 b的话 ,则交换两个数字的位置 使用 短路&&,扩展赋值运算符,位运算 4、条件运算符(三目运算) 单目(一元)运算符 :++,--,! 双目(二元)...
第一行包含两个整数 $N$、$M$,分别表示该数列数字的个数和操作的总个数。 第二行包含 $N$ 个用空格分隔的整数,其中第 $i$ 个数字表示数列第 $i $ 项的初始值。 接下来 $M$ 行每行包含 $2$ 或 $4$个整数,表示一...
9. 编程求 1+(1+2)+…+(1+2+…+n),n 的值由键盘输入。 该程序使用了for循环结构,通过变量j和sum来计算每一项的值,并将其累加到sum中。最后,使用printf函数将sum的值输出。 10. 从键盘输入 10 个整数,统计...