在學習過程中,遇到了兩道題目。卡了自己一段時間,通過查閱資料,已經AC。下面貼一下這兩道題目。
這道題是計算1~n的所有數字中,1出現的個數。這道題目是劍指offer中比較難的一道題目。首先考慮在計算過程中,有一定規律,但是在具體的coding過程中,總不能加各種if條件句判斷吧。所以通過查資料學習了這樣一種解決該問題的方法:
例如,n=abcde。首先,將n切分開來存放到數組之中。之後進行具體的邏輯判斷。以具體數值c爲例,需要考慮他的高位和低位情況,高位即ab的情況,低位即de的情況。
先不考慮c的具體值,先考慮c的高位的一個情況。00~ab-1,因爲當考慮的ab時,需要看c的情況,所以先判斷00~ab的一個情況,這時候其實可以直接算出來至少100種(00~99)之後需要考慮c的情況,如果c=0,則不考慮,如果c=1,則需要加上de+1(00~de)。如果c>1.則直接加100(00~99)。具體邏輯就是這樣
/***
* 設數字爲abcde,當前位數爲c位,
c位1的個數即爲高位個數+低位個數
高位範圍爲 00 ~ ab-1 :
有 ab*100 個(因爲c在百位)
低位分爲三種情況:
c = 0 ,有 0 個
c = 1 ,有 de + 1 個
c > 1 , 有 100 個 (因爲c在百位)
依次遍歷每一位數相加,即爲總共1的個數
* @param n
* @return
*/
public static int numberOf1Between1AndN_Solution(int n) {
if(n==0) {
return 0;
}
ArrayList<Integer>list=new ArrayList<>();
while(n!=0){
list.add(n%10);
n=n/10;
}
int size=list.size();
int res=0;
for (int i=size-1;i>=0;i--){
int left=0,right=0,t=1;
//處理第i位之前的數
for (int j=size-1;j>i;j--){
left=left*10+list.get(j);
}
//處理第i位之後的數
for (int j=i-1;j>=0;j--) {
right=right*10+list.get(j);
t=t*10;
}
//00~ab-1的情況
res+=left*t;
if (list.get(i)==1) {
res += right + 1;
}else if (list.get(i)>1){
res+=t;
}
}
return res;
}
第二道題目計算第n位數的具體數值。這道題目數學的味道比較濃厚。需要我們找一找固定的規律。
首先1位數有10中情況,2位數有90中情況,3位數有900種情況。。。
其次,我們需要根據n的具體值,來判斷第n位數所在的值是多少位數所組成。所以,需要根據具體的規律算出來。例如,確定好n在3位數中的某一個值的某一位上。需要對ceil(n/3)確定在第幾個數字上。之後需要n對i取模,計算在該值的第幾位上。
我們需要設置一個初始變量 i代表是幾位數的情況,s代表i位數有多少個,base代表i位數的起始值。
需要注意的是,爲了便於計算,我們規定起始值從1開始,這樣1位數有9種情況,2位數有90種情況,3位數有900中情況。。。便於計算。最終在計算第幾個數時,減去1即可。
public int digitAtIndex(int n) {
if (n==0) {
return 0;
}
/***
* i代表是幾位數,base代表i位數時的起始值,s代表i位數的個數
*/
long i=1,s=9,base=1;
while (n>i*s){
n= (int) (n-i*s);
i+=1;
base*=10;
s=s*10;
}
/**
* 剩下的n代表第i位後面的情況,number用於計算剩下的n應該在base的什麼位置,n/i需要向上取整
* 這裏最後減1是因爲需要考慮最開始的0.
* r用於計算n具體的位置。
*/
int number= (int) (base+(n+i-1)/i-1);
int r= (int) (n%i==0?i:n%i);
for (int j=0;j<i-r;j++){
number/=10;
}
return number%10;
}