查看匯總:2015軟件水平考試程序員精選題匯總
在從1到n的正數(shù)中1出現(xiàn)的次數(shù)
題目:輸入一個(gè)整數(shù)n,求從1到n這n個(gè)整數(shù)的十進(jìn)制表示中1出現(xiàn)的次數(shù)。
例如輸入12,從1到12這些整數(shù)中包含1 的數(shù)字有1,10,11和12,1一共出現(xiàn)了5次。
分析:這是一道廣為流傳的google面試題。用最直觀的方法求解并不是很難,但遺憾的是效率不是很高;而要得出一個(gè)效率較高的算法,需要比較強(qiáng)的分析能力,并不是件很容易的事情。當(dāng)然,google的面試題中簡(jiǎn)單的也沒(méi)有幾道。
首先我們來(lái)看最直觀的方法,分別求得1到n中每個(gè)整數(shù)中1出現(xiàn)的次數(shù)。而求一個(gè)整數(shù)的十進(jìn)制表示中1出現(xiàn)的次數(shù),就和本面試題系列的第22題很相像了。我們每次判斷整數(shù)的個(gè)位數(shù)字是不是1。如果這個(gè)數(shù)字大于10,除以10之后再判斷個(gè)位數(shù)字是不是1。基于這個(gè)思路,不難寫(xiě)出如下的代碼:
int NumberOf1(unsigned int n);
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in the integers between 1 and n
// Input: n - an integer
// Output: the number of 1 in the integers between 1 and n
/////////////////////////////////////////////////////////////////////////////
int NumberOf1BeforeBetween1AndN_Solution1(unsigned int n)
{
int number = 0;
// Find the number of 1 in each integer between 1 and n
for(unsigned int i = 1; i <= n; ++ i)
number += NumberOf1(i);
return number;
}
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in an integer with radix 10
// Input: n - an integer
// Output: the number of 1 in n with radix
/////////////////////////////////////////////////////////////////////////////
int NumberOf1(unsigned int n)
{
int number = 0;
while(n)
{
if(n % 10 == 1)
number ++;
n = n / 10;
}
return number;
}
這個(gè)思路有一個(gè)非常明顯的缺點(diǎn)就是每個(gè)數(shù)字都要計(jì)算1在該數(shù)字中出現(xiàn)的次數(shù),因此時(shí)間復(fù)雜度是O(n)。當(dāng)輸入的n非常大的時(shí)候,需要大量的計(jì)算,運(yùn)算效率很低。我們?cè)囍页鲆恍┮?guī)律,來(lái)避免不必要的計(jì)算。
我們用一個(gè)稍微大一點(diǎn)的數(shù)字21345作為例子來(lái)分析。我們把從1到21345的所有數(shù)字分成兩段,即1-1235和1346-21345。
先來(lái)看1346-21345中1出現(xiàn)的次數(shù)。1的出現(xiàn)分為兩種情況:一種情況是1出現(xiàn)在最高位(萬(wàn)位)。從1到21345的數(shù)字中,1出現(xiàn)在10000-19999這10000個(gè)數(shù)字的萬(wàn)位中,一共出現(xiàn)了10000(104)次;另外一種情況是1出現(xiàn)在除了最高位之外的其他位中。例子中1346-21345,這20000個(gè)數(shù)字中后面四位中1出現(xiàn)的次數(shù)是2000次(2*103,其中2的第一位的數(shù)值,103是因?yàn)閿?shù)字的后四位數(shù)字其中一位為1,其余的三位數(shù)字可以在0到9這10個(gè)數(shù)字任意選擇,由排列組合可以得出總次數(shù)是2*103)。
至于從1到1345的所有數(shù)字中1出現(xiàn)的次數(shù),我們就可以用遞歸地求得了。這也是我們?yōu)槭裁匆?-21345分為1-1235和1346-21345兩段的原因。因?yàn)榘?1345的最高位去掉就得到1345,便于我們采用遞歸的思路。
分析到這里還有一種特殊情況需要注意:前面我們舉例子是最高位是一個(gè)比1大的數(shù)字,此時(shí)最高位1出現(xiàn)的次數(shù)104(對(duì)五位數(shù)而言)。但如果最高位是1呢?比如輸入12345,從10000到12345這些數(shù)字中,1在萬(wàn)位出現(xiàn)的次數(shù)就不是104次,而是2346次了,也就是除去最高位數(shù)字之后剩下的數(shù)字再加上1。
基于前面的分析,我們可以寫(xiě)出以下的代碼。在參考代碼中,為了編程方便,我把數(shù)字轉(zhuǎn)換成字符串了。
#include "string.h"
#include "stdlib.h"
int NumberOf1(const char* strN);
int PowerBase10(unsigned int n);
/////////////////////////////////////////////////////////////////////////////
// Find the number of 1 in an integer with radix 10
// Input: n - an integer
// Output: the number of 1 in n with radix
/////////////////////////////////////////////////////////////////////////////
int NumberOf1BeforeBetween1AndN_Solution2(int n)
{
if(n <= 0)
return 0;
// convert the integer into a string
char strN[50];
sprintf(strN, "%d", n);
return NumberOf1(strN);
}
/////////////////////////////////////////////////////////////////////////////
相關(guān)推薦:
北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |