今天在牛客網上做劍指offer上的題,看到劍指offer上的解法確實沒不太好理解。這裏把看到的一種比較容易理解的方法記錄下來,便於整理思路:
原博客解釋的非常清楚,在這裏。
這道題是要求1-n,這裏總共出現了多少次1。
比如輸入爲12,則包含1的數字有1,10,11,12總共出現了五次。
那我們就從這個例子開始吧(本文會按照原文的記號來說明):
round=n/10,weight=n%10
首先我們來看個位:
12
如果只有2的話,出現了一次,記錄一下count=0+1=1;
12
再到十位,十位爲1,個位數字變化的只有0,1,2再加上本身的1位1,總共4次。那麼總共會出現的次數爲count=count+4=5
這個例子比較簡單,也不能說明什麼規律,再看一個例子:
678
首先是個位,
678,round=67(代表高位可以從0~9變化67次),base=1(代表當前在個位),weight=8(代表當前位的權重),count=0
那麼這時的高位可以循環67次,代表可以有67次個位數1的數字,加上個位數自己的一次總共爲count=67+1=68次。
678,round=6,base=10(十位),weight=7,count=68
此時,高位可以循環的有6*10=60次,7大於1,十位數爲1的也可以完全出現,所以count=count+6*10+10=138次
678,round=0,base=100(百位),weight=6,count=68
此時已經沒有比百位更高的位了,但是6是大於1的,所以可以出現1*100次完整的百位1,所以共計count=count+100=238次。
結束。
需要注意的是,出現多少次1和當期的weight是相關聯的,若當前爲weight=0,則不貢獻任何1,即爲前面的count。若當前爲1,如17,則可以貢獻個位數個數爲former(7)+1次,若大於1的話,意味着可以貢獻weight*base+base(當前weight位取1)個。
所以分爲三種情況:
當前weight=0:count=round*base
當前weight=1:count=roung*base+former+1
當前weight>1:count=round*base+base
public int NumberOf1Between1AndN_Solution(int n) {
int count =0;
int base=1;
int round=n;
while(round>0){
int weight=round%10;
round/=10;
count+=round*base;//公共部分
if(weight==1)
count+=(n%base)+1;
else if(weight>1)
count+=base;
base*=10;
}
return count;
}