1. 程式人生 > >LeetCode 233.數字1的個數 Number of Digit One

LeetCode 233.數字1的個數 Number of Digit One

題目連結

給定一個整數n,計算所有小於等於n的非負整數中數字1出現的個數。


0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98

99

我一開始的思路是,先計算個位1的個數,再計算高位1的個數。

個位1的個數好求,個位1的個數=(n%10>=1)?(n/10+1):(n/10)


就是高位1的個數我想的有些亂了。

比如,123和223,它們百位的1的個數分別是多少呢

123百位的1=123-100+1=24

223百位的1=100

於是可以知道,對於高位,是從==1和>1作為分界線。


可是,123和223,它們十位的1的個數分別是多少呢。在這裡我想了很久。

高位將次高位分成了若干份

123,1百將十位分成了兩份,0~99和100~123,相當於從0~99找1的個數*1+從0~23找1的個數

223,2百將十位分成了三份,0~99和100~199和200~223,相當於從0~99找1的個數*2+從0~23找1的個數

323,3百將十位分成了四份,0~99和100~199和200~299和300~323,相當於從0~99找1的個數*3+從0~23找1的個數


如果想通了這裡,就很好理解了。


於是思路變了。

程式碼如下:

class Solution {
public:
int calculate(int n,int k)
{
	if(n<1)	return 0;
	if(n<10)	return 1;//當n只有1位的時候
	int c;
	while(1)//這裡是為了保證k和n是相同位數
	{
		c=n/k;
		if(c!=0)	break;
		k/=10;
	}
	if(c==1)//當最高為為1的時候
	{
		return n-k+1+calculate(n-k,k/10)+calculate(k-1,k/10);//如果能理解最高位將次高位分成若干份這句話
	}
	else//當最高位>1的時候
	{
		return k+calculate(n-c*k,k/10)+c*calculate(k-1,k/10);
	}
}

int countDigitOne(int n) {
        int k=1;
        int m=n;
        while(m/=10)
        {
            k*=10;
        }
        return calculate(n,k);
    }
};