给定一个十进制数N,写下从1开始到N的所有整数,然后数一下其中出现的所有“1”的个数,比如:
1) N = 2 ,写下1、2,这样只出现1个“1”;
2) N= 12 ,我们会写下1、2、3、4、5、6、7、8、9、10、11、12,这样1的个数为5。
问题是:写一个函数f(N),返回1~N之间出现“1”的个数,比如:f(12) = 5。
这个题目带有几分找规律性质。本题解法可能较多,这里提供两种。
方法一:
// text.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
/****************************************************************
** Function name: oneNumber
** Descriptions: 计算1的个数
** input parameters: uliNumber:输入的数据,即为要计算1的个数的数据
** output parameters: void
** Returned value: uliCount:1的个数
****************************************************************/
unsigned long int oneNumber ( unsigned long int uliNumber )
{
/* 将uliNumber传进来的值赋给uliTally */
unsigned long int uliTally = uliNumber ;
/* 记录1的个数 */
unsigned long int uliCount = 0 ;
/* 提取位的权值 */
unsigned long int uliFlag = 1 ;
/* 提取位 */
unsigned int uiFlag = 0 ;
/* 提取位的幂次方 */
unsigned int uiLog = 0 ;
/*
*对数据逐位取提取位
*/
while ( ( uliTally / uliFlag ) != 0 )
{
/* 从左开始计算,依次取出uiFlag*10^n */
uiFlag = ( uliTally / uliFlag ) % 10 ;
/* 如果是 1 * 10^n ,则按1*10^n公式进行计算 */
if ( 1 == uiFlag )
{
uliCount += uiLog * ((unsigned long int)( uliFlag / 10)) + 1 ;
/* 加上10^n后面数据 */
uliCount += ( uliNumber % uliFlag ) ;
}
/*
*如果是 uiFlag * 10^n ,则按uiFlag*10^n公式进行计算
*/
else
{
/*( uliFlag ) * ( 1&&uiFlag )是为了uliFlag是0,则是加0 */
uliCount += ( uliFlag ) * ( 1&&uiFlag ) +
uiFlag * uiLog * ( (unsigned long int)( uliFlag / 10) ) ;
}
/* 依次向左取 */
uliFlag *= 10 ;
/* uiLog = log10(uliFlag) */
uiLog += 1 ;
}
/* 返回1的个数 */
return uliCount ;
}
/****************************************************************
** Function name: main
** Descriptions: 输入输出
** input parameters: argc , argv[]
** output parameters: void
** Returned value: 0
****************************************************************/
int main(int argc, char* argv[])
{
unsigned long int iNumber = 0 ;
unsigned long int uliCountNumber = 0 ;
printf("请输入iNumber: ") ;
scanf("%ld" , &iNumber) ;
uliCountNumber = oneNumber(iNumber) ;
printf( "1~%d中1的个数为: %dn" , iNumber , uliCountNumber ) ;
return 0;
}
函数头文件这里使用的是英语,但是格式是不变的。
编译结果:
请输入iNumber: 100
1~100中1的个数为: 21
请按任意键继续. . .
方法二:
// text.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
/****************************************************************
** Function name: oneNumber
** Descriptions: 计算1的个数
** input parameters: uliNumber:输入的数据,即为要计算1的个数的数据
** output parameters: void
** Returned value: uliCount:1的个数
****************************************************************/
unsigned long int oneNumber ( unsigned long int uliNumber )
{
/*
** 记录1的个数
*/
unsigned long int uliCount = 0 ;
/*
** 提取位左边的数
*/
unsigned long int uliLeft = 0 ;
/*
** 提取位右边的数
*/
unsigned long int uliRight = 0 ;
/*
** 提取位,此位对1进行计数
*/
unsigned long int uliFlag = 0 ;
/*
** 提取位的权值
*/
unsigned int uiFlag = 1 ;
/*
** 对数据逐位取提取位
*/
while ( (uliNumber / uiFlag)!=0 )
{
/*
** 提取位右边的数
*/
uliRight = uliNumber % uiFlag ;
/*
** 提取位
*/
uliFlag = ( uliNumber / uiFlag ) % 10 ;
/*
** 提取位左边的数
*/
uliLeft = ( uliNumber / uiFlag ) / 10 ;
/*
** 判断提取位,分成0、1和大于等于2这三种情况
*/
switch ( uliFlag )
{
/*
** 如果提取位为0,那么1的个数等于提取位左边数乘以取提取位的数据
*/
case 0 :
{
uliCount += uliLeft * uiFlag ;
} break ;
/*
** 如果提取位为1,那么1的个数等于提取位左边数乘以取提取位的数据
** 再加上(0到提取位右边数)+1
*/
case 1 :
{
uliCount += uliLeft * uiFlag + uliRight + 1 ;
} break;
/*
** 如果提取位大于1,那么1的个数等于(提取位左边数+1)乘以
** 取提取位的数据
*/
default :
{
uliCount += ( uliLeft + 1 ) * uiFlag ;
} break;
}
/*
** 提取位向左移动一位
*/
uiFlag *= 10 ;
}
/*
** 返回1的个数
*/
return uliCount ;
}
/****************************************************************
** Function name: main
** Descriptions: 输入输出
** input parameters: argc , argv[]
** output parameters: void
** Returned value: 0
****************************************************************/
int main(int argc, char* argv[])
{
unsigned long int iNumber = 0 ;
unsigned long int uliCountNumber = 0 ;
printf("请输入iNumber: ") ;
scanf("%ld" , &iNumber) ;
uliCountNumber = oneNumber(iNumber) ;
printf( "1~%d中1的个数为: %dn" , iNumber , uliCountNumber ) ;
return 0;
}