劍指 Offer 43. 1~n整數中1出現的次數

1~n整數中1出現的次數

問題來源

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/
在這裏插入圖片描述

暴力法

對於暴力的方法,只需要從1開始,對1 -> n 中的所有數進行枚舉,然後依次判斷該數的每一位(個位,十位,百位 .... ....)是否爲1

  • 如果該位是1,計數器 ans++
  • 如果該位不是1,繼續判斷下一位
	int countDigitOne(int n) {
        int ans = 0;
        
        for(int i = 1; i <= n; i++)
        {
            int num = i;
            while(num)
            {
                if(num % 10 == 1)
                    ans++;
                num /= 10;
            }
        }

        return ans;
    }

當數據量特別大的時候,最後的結果是會超時的
在這裏插入圖片描述

優化後的寫法

既然暴力的方法不可以,那麼我們是否可以根據當前位(個位,十位,百位 .... ....)的數字,然後確定出以該位爲中心,一共有多少個1的情況。

對於這種做法,我們可以把一個數字(n n-1 … … 1)分成三部分,設當前位爲第 x 位:

  • 高位,n - > x + 1 位,也就是 n n-1 … … x + 1
  • 當前位,第 x 位,也就是 x
  • 低位,x-1 x-2 … … 1,也就是 x - 1 x - 2 1

在這裏插入圖片描述
對於當前位的數值,有這麼幾種情況

  1. 當前位的數值爲 0 ,也就是 x = 0

在這裏插入圖片描述

  1. 當前位的數值爲1,也就是 x = 1

  2. 當前位的數值大於1,也就是 x > 1

在這裏插入圖片描述

    int countDigitOne(int n) {
        int ans = 0;
        long i = 1; //i表示哪一位的數字,i = 1表示個位,i = 10 表示十位

        while(n / i != 0)
        {
            //當前位的高位數字
            long high = n / (10 * i);
            //當前位的數字
            long cur = (n / i) % 10;
            //當前位的低位數字
            long low = n - (n / i) * i;

            if(cur == 0)
                ans += high * i;
            else if(cur == 1)
                ans += high * i + low + 1;
            else
                ans += (high + 1) * i;

            i *= 10;
        }
        return ans;
    }

算法的時間複雜度爲O(log n),也就是 n 有多少位,就循環多少次

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章