1. 程式人生 > 實用技巧 >【LeetCode-數學】1~n整數中1出現的次數

【LeetCode-數學】1~n整數中1出現的次數

題目描述

輸入一個整數 n ,求1~n這n個整數的十進位制表示中1出現的次數。

例如,輸入12,1~12這些整數中包含1 的數字有1、10、11和12,1一共出現了5次。

示例:

輸入:n = 12
輸出:5

輸入:n = 13
輸出:6

說明:
1 <= n < 2^31
題目連結: https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/

思路

由於 n 的範圍非常大,所以暴力求解是行不通的。

假設 n 是 x 位數,第 i 位表示為 \(n_i\),所以 \(n=n_xn_{x-1}\dots n_1\)

。我們從第 i 位 \(n_i\) 將 n 分為兩個部分:

  • \(n_xn_{x-1}\dots n_{i+1}\) 被稱為高位 high;
  • \(n_{i-1}n_{i-2}\dots n_1\) 被稱為地位 low;
  • \(n_i\) 被稱為當前位 cur;
  • \(10^i\) 稱為位因子,記為 digit;

high、low、cur、digit 的初始化為:

int high = n/10;
int low = 0;
int cur = n%10;
long digit = 1; // long 型別,否則會溢位

high、low、cur、digit 的更新方法為:

low += cur*digit;
cur = high%10;
high /= 10;
digit *= 10;

在每一步,我們根據 high、low、cur、digit 的情況來計算 1 的個數 ans,具體分 3 種情況:

  • cur==0,此時 ans += high*digit;
  • cur==1,此時 ans += hight*digit+low+1;
  • cur==2~9 的情況,ans += (high+)*digit;

這篇題解舉了幾個例子來介紹為什麼要這麼做。

程式碼如下:

class Solution {
public:
    int countDigitOne(int n) {
        int high = n/10;
        int low = 0;
        int cur = n%10;
        long digit = 1;  // long 型別,否則會溢位
        int ans = 0;
        while(high!=0 || cur!=0){  // 注意條件
            if(cur==0) ans += high*digit;
            else if(cur==1) ans += high*digit+low+1;
            else ans += (high+1)*digit;

            low += cur*digit;
            cur = high%10;
            high /= 10;
            digit *= 10;
        }
        return ans;
    }
};
  • 時間複雜度:O(logn)
  • 空間複雜度:O(1)

參考

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/