1. 程式人生 > >【LeetCode 233】所有小於等於n的整數中,1出現的總次數,(例如111算3次)

【LeetCode 233】所有小於等於n的整數中,1出現的總次數,(例如111算3次)

聽說找工作的都推薦刷LeetCode,那我也搭配著做一些。

題目連結:

https://leetcode.com/problems/number-of-digit-one/

/*

題目:
給一個n, 找出從1到<=n,裡所有整數的每一位上出現的1的總次數,例如n = 13, 則1,10,11,12,13,有6個1


思路:
暴力解法O(n), 當n到10^9會超時,故需要找規律


分析可得
0 - 9:1個
10 - 99:10 + 9 * 1
100 - 999:100 +9 * (10 + 9 * 1 + 1)
1000 - 9999:1000 + 9 * sum(2)
...


so:
1. 求出n的最高位,得到<=最高位-1位的sum
2. 加上當前最高位的,分為high==1, high>1,
3. 最高位得到的1的總個數 + 去掉最高位的總個數,迭代

*/

// 2016-5-5 20:17:32
// 2016-5-5 21:21:40

#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;

_int64 a[10]; // 改成long long
_int64 sum[10];
int init = 0;
class Solution {
public:
    int countDigitOne(int n) {
		int i, j;
		if (init == 0) {
			a[0] = 1;
			sum[0] = a[0];
			for (i = 1; i <=9; i++) {
				a[i] = pow(10, i) + 9 * sum[i - 1];
				sum[i] = sum[i - 1] + a[i];
			}
			init = 1;
			/*
			for (i = 0; i<= 9; i++) {
				printf("%I64d ", a[i]);
			} printf("\n");
			for (i = 0; i<= 9; i++) {
				printf("%I64d ", sum[i]);
			} printf("\n");
			*/
			
		}
		if (n <= 0) return 0;
		
		int num[10];
		int nBit = 0;
		int n2 = n;
		while (n2 != 0) {
			num[nBit++] = n2 % 10;
			n2 /= 10;
		}
		if (nBit == 1) {
			if (n >= 1) return 1;
			return 0;
		}

		int ans = 0;
		
		//
		ans += sum[nBit - 2];
		int high = num[nBit - 1];
		int low = n - high * pow(10, nBit - 1);
		if (high == 1) {
			ans += low + 1;
			
		} else {
			ans += pow(10, nBit - 1);
			ans += (high - 1) * sum[nBit - 2];
		}
		ans += countDigitOne(low);
		return ans;
    }
};


int main() {
	Solution s;
	cout<< s.countDigitOne(1234567890) << endl;
	return 0;
}