題目
輸入一個整數n,求從1到n這n個整數的十進制表示中1出現的次數。例如輸入12,從1到12這些整數中包含1的數字有1,10,11和12,1一共出現了5次
PS:牛客鏈接,LeetCode鏈接
方法一(Brute Force)
思路: 直接遍歷1~n之間的每個數字,每次循環使用先取餘(%10)後自除以10的方式,統計每個數字的各個數位上1出現的次數,並累加,然後返回總和
複雜度分析: 時間複雜度:O(n*logn),空間複雜度:O(1)
代碼: 略
方法二
思路: 將n的各個數位的值能夠在0~9之間任意變換組合。分別將各個數位設置成數字1,在保證整體值不大於n的情況下,觀察其他數位上的數的變化範圍,統計滿足條件的組合個數,即某個數位上值爲1的數字有多少個,最後將各個數位值爲1的情況下的組合個數求和即可。
舉例1:當n=2020時,計算其百位上爲1時的組合個數
舉例2:當n=2120時,計算其百位上爲1時的組合個數
舉例3:當n=2220時,計算其百位上爲1時的組合個數
規律總結:
設x
爲數n
的右邊起第i(i>=0)
個數位上的數值,left
爲n中第i
位左側數字組成的值,right
爲n中第i
位的右側數字組成的值,則:
1. 當x==0時: 當前數位上值爲1的組合值個數爲left*10^i
2. 當x==1時: 當前數位上值爲1的組合值個數爲left*10^i+right+1
3. 當x>1時: 當前數位上值爲1的組合值個數爲(left+1)*10^i
舉例4:當n=2134時,計算1~n中數字1出現的次數
若n的個位爲1: 組合數爲214種
若n的十位爲1: 組合數爲220種
若n的百位爲1: 組合數爲200+35=255種
若n的千位爲1: 組合數爲1000種
共計1669種組合,即在1~2134範圍內的整數中,1出現的次數爲1669次
本人代碼(Java):
public class Solution {
public int countDigitOne(int n) {
// 左側數值,當前數位的數值,右側數值
long leftNum,curNum,rightNum;
// 當前數位,數字1出現的次數
long k = 1,count = 0;
while(k<=n){
leftNum = n/k/10;
curNum = n/k%10;
rightNum = n%k;
if(curNum == 1) count += leftNum*k+rightNum+1;
else if(curNum > 1) count += (leftNum+1)*k;
else count += leftNum*k;
k*=10;
}
return count;
}
}
複雜度分析: 時間複雜度:O(logn),空間複雜度:O(1)
大神代碼(Java):
public int countDigitOne(int n) {
int count = 0;
for (long k = 1; k <= n; k *= 10) {
long r = n / k, m = n % k;
// sum up the count of ones on every place k
count += (r + 8) / 10 * k + (r % 10 == 1 ? m + 1 : 0);
}
return count;
}