整数中x出现的次数
码文不易,如果帮助到您,希望您可以下载一个压缩包,与您无害,与我有益谢谢支持原创
欢迎大家阅读我的博客,如果有错误请指正,有问题请提问,我会尽我全力改正错误回答问题。在次谢谢大家。
码文不易,如果帮助到您,希望您可以下载一个压缩包,与您无害,与我有益谢谢支持原创
实验环境
- 语言c/c++
- 编译器devc++5.11/5.40
实验内容与要求
输入
输入为一行,为一个整数 n (1 ≤ n ≤ 10^9),为一个整数 x (0 ≤ x ≤ 9)。
输出
将从 1 到 n (包括 1 和 n) 的每一个数的十进制表示中的x个数 ,输出x个数总数。
样例输入
2499 0
样例输出
689
总时间限制: 1000ms 内存限制: 256000kB
目录
码文不易,如果帮助到您,希望您可以下载一个压缩包,与您无害,与我有益谢谢支持原创
实验解析
思路
前言
解决这类问题,最好的方法是,先构造出对应的数学模型,然后根据数学模型来编写程序,这样事半功倍。像我这样的小白,第一次总是手忙脚乱的上来就编,边写边想,极容易出错,也会使自己十分紧张,打乱节奏。希望看到本文的童鞋们引以为戒。
举例
这道题呢,我的想法是一位一位的看,从高位开始还是低位开始影响不大。
比如,1234这个数,找3出现的次数,从高位开始:
- 1<3,又是最高位说明 3 不会出现在千位,出现次数 + 0*1000 + 0*100
- 2<3,考虑到高位是1,出现次数+1*100 +0*10
- 3=3,高位为2,出现次数+ 12*10 + 4*1+1
- 4>3,高位为3,出现次数+ (123+1) * 1
有没有找到些规律呢?
分类讲解
没明白的话,我们来讨论一些简单的例子,懂了的童鞋可以跳过。比如,1111这个数,找1出现的次数,从高位开始:
对应位正好就等于要找的数
- 首位正好就等于要找的数,这时因为没有高位了,让我们可以只思考低位对其影响。1出现千位的次数就等于低位111+1。这个1代表什么呢?1000。那111呢?1001,1002···1111,是不是有些明白了呢
- 然后是次高位,也正好是1,低位如何考律我们已经明白了,就是11+1嘛。这时有高位的问题,高位是1,所以要加上1*100,这个100代表什么呢?100,101···199。这时候有人问了我们这一步步算的是啥?第一步算的是1出现在千位的次数,这步算的是1出现在百位的次数,这样,每位出现多少次加到一起不就是总量了么。
- 十位也一样不再过多赘述 110+1+1
- 个位就不再有低位所以就是111
有没有找到些规律呢?这是相等时的算法
对应位正好就大于要找的数
当大于要找的数时低位的影响就消失了,比如121 找1 十位肯定经历了 110 111 所以 计算十位时相当于(1+1)*10
对应位正好就小于要找的数
小于要找的数也不用考虑低位,因为压根就没有出现 101 找1 十位 就是 1*10
‘0‘
这是我们发现0这个数字不符合现有情况,所以单独考虑
- 当前是0,高位不可能是零,最低是1,与其他数相比整体位移,高位-1乘上当前位,以及低位+1
- 当前大于,高位可能是零,与其他数相比整体位移,高位乘上当前位
总结
每位的算法分为两部分:
1. 非零数字分三类
1. 小于要找的数:只看高位乘上当前位,例如4321 百位 4*100
2. 大于要找的数:只看高位+1乘上当前位,例如4321 百位 (4+1)*100
3. 等于要找的数:要考虑高位乘上当前位,以及低位+1,例如4321 百位 4*100+21+1
2. 零分两类
1. 当前是0,高位不可能是零,最低是1,与其他数相比整体位移,高位-1乘上当前位,以及低位+1
2. 当前大于,高位可能是零,与其他数相比整体位移,高位乘上当前位
定义说明
#include <iostream>//输入输出
#include <string.h>//字符串
using namespace std;
//函数声明
inline getnum(long &c,int &x);//输入
long getcount(long c, int x );//获取结果
函数说明
功能函数
获取输入
inline getnum(long &c,int &x){//获取数 换成赛艇的数字
cin>>c; //获取n
cin>>x;//获取x
}
获取结果
long getcount(const long c,const int x ){
long high = c,temp,low;
long count =0;
int curr,i = 10;
if(x == 0){
while(high>0){
high = c/i;//高位
temp = c%i;
curr = temp /(i/10);//当前位
low = temp %(i/10);//低位
if(curr == 0){
count +=( high-1)*(i/10)+low+1;
}else if(curr > 0){
count += high *(i/10);
}
i*=10;
}
}else{
while(high>0){
high = c/i;//高位
temp = c%i;
curr = temp /(i/10);//当前位
low = temp %(i/10);//低位
if(curr == x){
count += high*(i/10)+low+1;
} else if(curr > x){
count += (high+1)*(i/10);
}else{
count += high*(i/10);
}
i*=10;
}
}
return count;
}
从低位开始,与之前分析相反,童鞋们正好可以自己验算一遍。
主函数
main(){
long num;
int x;
getnum(num,x);
num = getcount(num,x);
cout<<num<<endl;
}
结果展示
附录
相关资料
源代码
码文不易,如果帮助到您,希望您可以下载一个压缩包,与您无害,与我有益谢谢支持原创
>
第一版
#include <iostream>
#include <string.h>
using namespace std;
//函数声明
inline getnum(long &c,int &x);
long getcount(long c, int x );
main(){
long num;
int x;
getnum(num,x);
num = getcount(num,x);
cout<<num<<endl;
}
inline getnum(long &c,int &x){//获取数 换成赛艇的数字
cin>>c;
cin>>x;
}
long getcount(const long c,const int x ){
long high = c,temp,low;
long count =0;
int curr,i = 10;
if(x == 0){
while(high>0){
high = c/i;
temp = c%i;
curr = temp /(i/10);
low = temp %(i/10);
if(curr == 0){
count +=( high-1)*(i/10)+low+1;
}else if(curr > 0){
count += high *(i/10);
}
i*=10;
}
}else{
while(high>0){
high = c/i;
temp = c%i;
curr = temp /(i/10);
low = temp %(i/10);
if(curr == x){
count += high*(i/10)+low+1;
} else if(curr > x){
count += (high+1)*(i/10);
}else{
count += high*(i/10);
}
i*=10;
}
}
return count;
}
码文不易,如果帮助到您,希望您可以下载一个压缩包,与您无害,与我有益谢谢支持原创
第二版
#include <iostream>
#include <string.h>
using namespace std ;
class Solution {
public:
long n;
int x;
long NumberOf1Between1AndN_Solution(){
long ones = 0;
if(x!=0)
for (long m = 1; m <= n; m *= 10)
ones += (n/m + 9-x) / 10 * m + (n/m % 10 == x) * (n%m + 1);
else
for (long m = 1; m <= n; m *= 10)
ones += (n/m -1) / 10 * m + (n/m % 10 == 0) * (n%m + 1);
return ones;
}
inline getnum(){//获取数 换成赛艇的数字
cin>>n;
cin>>x;
}
};
main(){
long num;
int x;
Solution s;
s.getnum();
num = s.NumberOf1Between1AndN_Solution();
cout<<num<<endl;
}
码文不易,如果帮助到您,希望您可以下载一个压缩包,与您无害,与我有益谢谢支持原创