題目描述
我的想法,一開始想用String的contains方法,但是有一個問題,如果是11,contians方法只能記錄一個1,輸出就少一個。
因此我在contians方法下面再調整了一下,如果contians,把這個String再賦給char[] (因爲String的底層就是char),這樣再來判斷
最後AC的代碼是 61ms 2713K
import java.util.*;
public class Solution {
public static int NumberOf1Between1AndN_Solution(int n) {
// HashMap map=new HashMap();
int sum=0;
String s="";
for(int i=1;i<=n;i++){
s=Integer.toString(i);
// map.add(s);
if(s.contains("1")){
// sum++;
char [] c=s.toCharArray();
for(int j=0;j<c.length;j++){
if(c[j]=='1'){
sum++;
}
}
}
}
return sum;
}
}
看一下別的解法:從數字出發找規律。
【其實開始我也想過這個是有規律的,動手分析了一下200以內的數字】
1-10:1 【1】
10-20:10 11 12 13 14 15 16 17 18 19 【10】
20-100: 21 31 41 51 61 71 81 91 【8】
100-110: 100 101 【1+1】
110-120: 110 111 112 113 114 115 116 117 118 119 【10】
120-200: 120 121 130 131 140 141 150 151 160 161 170 171 180 181 190 191 【2*8】
但是我的想法是,是不是可以先這樣去劃定區間,比如n=50,那麼1+10肯定有了,再從20-50來一個一個計算。
但是我覺得這個想法不夠好,因此用了上面的方法,不優雅,暴力的解決了。
編程之美上給出的規律: 1. 如果第i位(自右至左,從1開始標號)上的數字爲0,則第i位可能出現1的次數由更高位決定(若沒有高位,視高位爲0),等於更高位數字X當前位數的權重10i-1。 2. 如果第i位上的數字爲1,則第i位上可能出現1的次數不僅受更高位影響,還受低位影響(若沒有低位,視低位爲0),等於更高位數字X當前位數的權重10i-1+(低位數字+1)。 3. 如果第i位上的數字大於1,則第i位上可能出現1的次數僅由更高位決定(若沒有高位,視高位爲0),等於(更高位數字+1)X當前位數的權重10i-1。 二、X的數目 這裏的 X∈[1,9] ,因爲 X=0 不符合下列規律,需要單獨計算。 首先要知道以下的規律:
依此類推,從 1 至 10 i ,在它們的左數第二位(右數第 i 位)中,任意的 X 都出現了 10 i−1 次。 這個規律很容易驗證,這裏不再多做說明。 接下來以 n=2593,X=5 爲例來解釋如何得到數學公式。從 1 至 2593 中,數字 5 總計出現了 813 次,其中有 259 次出現在個位,260 次出現在十位,294 次出現在百位,0 次出現在千位。 現在依次分析這些數據,首先是個位。從 1 至 2590 中,包含了 259 個 10,因此任意的 X 都出現了 259 次。最後剩餘的三個數 2591, 2592 和 2593,因爲它們最大的個位數字 3 < X,因此不會包含任何 5。(也可以這麼看,3<X,則個位上可能出現的X的次數僅由更高位決定,等於更高位數字(259)X101-1=259)。 然後是十位。從 1 至 2500 中,包含了 25 個 100,因此任意的 X 都出現了 25×10=250 次。剩下的數字是從 2501 至 2593,它們最大的十位數字 9 > X,因此會包含全部 10 個 5。最後總計 250 + 10 = 260。(也可以這麼看,9>X,則十位上可能出現的X的次數僅由更高位決定,等於更高位數字(25+1)X102-1=260)。 接下來是百位。從 1 至 2000 中,包含了 2 個 1000,因此任意的 X 都出現了 2×100=200 次。剩下的數字是從 2001 至 2593,它們最大的百位數字 5 == X,這時情況就略微複雜,它們的百位肯定是包含 5 的,但不會包含全部 100 個。如果把百位是 5 的數字列出來,是從 2500 至 2593,數字的個數與百位和十位數字相關,是 93+1 = 94。最後總計 200 + 94 = 294。(也可以這麼看,5==X,則百位上可能出現X的次數不僅受更高位影響,還受低位影響,等於更高位數字(2)X103-1+(93+1)=294)。 最後是千位。現在已經沒有更高位,因此直接看最大的千位數字 2 < X,所以不會包含任何 5。(也可以這麼看,2<X,則千位上可能出現的X的次數僅由更高位決定,等於更高位數字(0)X104-1=0)。 到此爲止,已經計算出全部數字 5 的出現次數。 總結一下以上的算法,可以看到,當計算右數第 i 位包含的 X 的個數時:
相應的代碼非常簡單,效率也非常高,時間複雜度只有 O( log 10 n) 。 |
大神的代碼,38ms,528K
import java.util.*;
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int count = 0;//1的個數
int i = 1;//當前位
int current = 0,after = 0,before = 0;
while((n/i)!= 0){
current = (n/i)%10; //高位數字
before = n/(i*10); //當前位數字
after = n-(n/i)*i; //低位數字
//如果爲0,出現1的次數由高位決定,等於高位數字 * 當前位數
if (current == 0)
count += before*i;
//如果爲1,出現1的次數由高位和低位決定,高位*當前位+低位+1
else if(current == 1)
count += before * i + after + 1;
//如果大於1,出現1的次數由高位決定,//(高位數字+1)* 當前位數
else{
count += (before + 1) * i;
}
//前移一位
i = i*10;
}
return count;
}
}