目录
原思路
原代码
思路优化
优化代码
问题意思是输入两个数字,m,n,从1到m中,数字n出现的次数,例如输入11,1。1~11中1总共出现了4次。
原思路:从1开始进入循环,若m处于1到9之间,当n==i时,定义计数器temp+1.若m大于9,则进行求每一位数字,方法如下:首先用i对10取余,得到个位,然后i/10,然后再次取余,得到十位,循环下去得到每一位数字,循环停止条件为i的值为0.在循环中加入判断条件,如果取余的结果(每个位上的数字)等于你,则计数器加一。此处数字位数的循环应在循环外进行标记,因为循环结束的条件位i==吗,若不加标记,则循环无法结束。
源代码:
int vs(int m, int n)
{
int p=0;//计数器
int vlan;//标记
for (int i = 1; i<=m; i++)
{
vlan = i;
if (i == n) p++;
else {
while (i != 0)
{
if (i % 10 == n) p++;//余数(每一位数字)等于n,计数器加一
i /= 10;
}
i = vlan;//循环结束之后i会变为0,需要利用标记进行重新赋值
}
}
return p;
}
int main()
{
int m, n;
scanf("%d", &m);
scanf("%d", &n);
int p=vs(m, n);
printf("%d", p);
}
思路优化:以上代码位最普遍的思路,强行进行计算求和,不建议使用。优化思路如下:
最简单的方式就是利用公式求在各位,十位,百位上的出现次数,然后求和便是想要的结果。首先要知道规律:1~10之间出现数字次数位1,1~100之间出现次数为10,1~1000出现次数为100,很显然可以看出规律1~(10^i)中出现数字n的次数为(10^(i-1));有了这个规律,接下来就很简单。我们首先用举例,然后再例子中找规律。
我们以在1~3657中找6为例,
个位开始计算,高位是365(3657/10),此时1~3650中,出现6的次数为高位*1,即365,然后看本位,即7,因为7>6,1~7中只能存在一个6,所以+1,结果为365+1=366;
其次是十位,高位是36(3657/100),此时1~3600中出现6的次数为高位*10,即360,本位为5,因为5<6,所以不做计算,结果为360;
接着是百位,高位为3,(3657/1000),此时1~3000中6出现的次数为高位*100,即300,本位为6,因为6==6,所以此处3000~3657中6出现的次数肯定不够60(6*10),应该这么算57+1(57为低位),低位+1.所以结果是58+300=358.
最后是千位,无高位,本位为3,3<6,所以此处无6,
最终结果为366+360+358=1084.
我们可以找到规律,
1)取基础值,首先应该取高位数字即(m/(10^(i+1))),此处i为位数(个位 0,十位 1...),若存在高位,即计数器加高位*(10^(i+1)),若不存在则为0,基础值便是高位*(10^(i+1)。
2)取修正值,即用本位(m)和要查找的数字(n)作比较,
当m>n时,修正值为(10^i),
当m==n时 直接带入公式,低位+1
当m<n时,无修正值。
优化代码:
int vs(int n, int x)
{
int count=0, k;
for (int i = 1; k = n/i; i *= 10)
{//k/10为高位
count+=( k / 10)*i;
int m= k % 10;//当前位的数
if (m > x)
{
count += i;
}
else if (m == x)//低位+1
{
count += n - k*i + 1;//(n-k*i)为低位
}
}
return count;
}
int main()
{ int m,n;
scanf("%d", &m);
scanf("%d", &n);
int p=vs(m, n);
printf("%d", p);
}
循环的节指条件便是本位为0,很显然这段代码比较与原来的代码,运算效率提高了很多,建议使用。