1-N的自然序列中1出现的次数

在《编程之美》中看到过这道题,在《编》中求第 i 位数字贡献的次数时还需要考虑 i之前和之后的数字,计算也蛮麻烦的。

后来搜了一些网友的IDEA,发现了更好的解法,先自己总结如下:

 

首先我们通过两个例子来理解这个规律,我们把计算这个出现次数的函数记为 f(n)。

1.   n=12345时, 首位为1。如果我们模拟这个1-n的序列,我们发现从 0 ~ 9999 时,首位并未出现,所以此时1出现的次数为 f(9999);然后从10000~12345时,首位1出现了 0~2345即(2345+1)次,而在从10000~12345递增的过程中,后四位数字也有1出现,而且与首位的1是无关的,即这个过程中后四位出现的次数是与从0~2345中出现的次数是等价的,即f (2345) ;

    所以对n=12345来讲,f (12345) = f(9999) + 2345+1 + f( 2345) ;

2.n=56789,即首位不为1的时候。与第一种情况类似,我们此时可以将0~n的递增氛围四个区段: 0~9999 ; 10000~ 19999 ; 20000 ~ 49999 ; 50000 ~ 56789 ;

   第一个区段中1出现的次数与首位是无关的,所以是 f ( 9999 ) ;

   第二个区段首位一直保持为1,总共出现了10000次,后四位贡献了 f( 9999) 次,分析与 第一种情况相同的;

   第三个区段中首位一直不为1,所以等价于后四位的递增,但注意这个完整的递增出现了3次(20000~29999;30000~39999;40000~49999),所以是 (5-2)* f(9999)次;

   第四个区段中首位也一直不为1,所以等价于后四位的递增,即0~6789,所以是 f(6789 )次;

  所以 f (n ) = f (56789 ) =  (5-2+2) * f( 9999 ) + 10000 + f(6789 ) 次;

 

分析到这里应该很好写代码了,改天写一个贴上来。

说不如做,现在就写吧。

#include<iostream>
#include<vector>
using namespace std;

long long  find1(int n)
{
	if(n<10)
	{
		return n>=1?1:0;
	}
	int factor=1;
	while(factor<=n)
	{
		factor*=10;
	}
	factor/=10;
	int first=n/factor;
	long long  res=0;
	if ( first==1 )
	{
		int other = n%factor;
		res= other+1+ find1(factor-1)+find1(other);
	}
	else
	{
		int other = n%factor;
		res= first*find1(factor-1) + find1(other)+factor;
	}
	return res;
}


int main()
{
	int n;
	scanf("%d",&n);
	long long  res=find1(n);
	printf("%ld\n",res);
}

测试数据用的:http://pat.zju.edu.cn/contests/pat-practise/1049,代码已通过测试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我们可以将这道题分成两个子问题:首先,我们需要找到在给定范围 [m, n] 数字 n 出现的总次数;其次,我们需要将这个总次数拆分成各个位数上数字 n 出现次数。 对于第一个子问题,我们可以遍历 [m, n] 的每一个数字,计算数字 n 出现次数,并累加到总次数。 对于第二个子问题,我们可以将数字 n 拆分成各个位数上的数字,然后分别统计每个位数上数字 n 出现次数。具体地,假设数字 n 有 k 位,我们可以使用一个数组 count 来记录在个位、十位、百位......上数字 n 出现次数,然后将其累加起来即可。 下面是代码实现: ```python def count_digit(n, d): """ 统计数字 n 数字 d 出现次数 """ count = 0 while n > 0: if n % 10 == d: count += 1 n //= 10 return count def count_range(m, n, d): """ 统计在范围 [m, n] 数字 d 出现次数 """ count = 0 for i in range(m, n+1): count += count_digit(i, d) return count def count_range_all_digits(m, n): """ 统计在范围 [m, n] 所有数字出现次数 """ count = [0] * 10 # 初始化 count 数组 for d in range(10): count[d] = count_range(m, n, d) return count ``` 其,`count_digit(n, d)` 函数用于统计数字 n 数字 d 出现次数;`count_range(m, n, d)` 函数用于统计在范围 [m, n] 数字 d 出现次数;`count_range_all_digits(m, n)` 函数用于统计在范围 [m, n] 所有数字出现次数,并返回一个包含 0~9 共 10 个数字在范围 [m, n] 出现次数的列表 count。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值