1. 程式人生 > >PAT-ADVANCED1049——Counting Ones

PAT-ADVANCED1049——Counting Ones

題目描述:

題目翻譯:

1049 計算1的個數

任務很簡單:給定任何正整數N,你應該計算從1到N的整數的十進位制形式的1的總數。例如,給定N為12,在1, 10, 11, 12中有5個1。

輸入格式:

每個輸入檔案包含用一個測試用例。該測試用例給出了一個正整數N(<= 2 ^ 30)。

輸出格式:

對每個測試用例,在一行中輸出1的個數。

輸入樣例:

12

輸出樣例:

5

知識點:數學

思路:統計每一位在1 ~ N的過程中可能出現1的次數

如果通過從1數到n一個個列舉來算1的個數,測試點4和測試點6會超時。

這個思路很巧妙,是分別統計每一位在1 ~ N的過程中可能出現的次數,再累加即得1的個數總和

。以輸入資料為30710來舉例說明整個過程。

(1)以字串的形式接收資料,遍歷該字串的每一位。

(2)對於字串的首位(首位不可能是0),首位的左邊沒有數字,首位右邊的數字是right。

a:如果首位是1,為了不超過N,對於右邊的數字我們可以取0 ~ right,總共有right + 1種情況。

b:如果首位不是1,對於30710來說,1後面的數字可以取0 ~ 9999,共10000種情況。

(3)對於字串的末位,末位的右邊沒有數字,末位左邊的數字是left。

a:如果末位是0,則其左邊可以取的範圍是0 ~ left - 1,共left種情況,對於30710來說,末位0前面可以取0 ~ 3070。

b:如果末位不是0,則其左邊可以取的範圍是0 ~ left,共left + 1種情況。

(4)對於既不是字串首位也不是字串末位的情況,其左邊的數字是left,右邊的數字是right。

a:如果當前位的是0,則其左邊可以取的範圍是0 ~ left - 1,對於30710的中間的0來說,右邊可以取的範圍是0 ~ 999。共left * 1000種情況。

b:如果當前位的是1,對於30710的中間的1來說,當左邊取0 ~ 306時,右邊可以取0 ~ 9;當左邊取307時,右邊只能取0。

c:如果當前位既不是0也不是1,對於30710的中間的7來說,左邊可以取0 ~ 30,右邊可以取0 ~ 99。

時間複雜度是O(n ^ 2),其中n為N的位數。空間複雜度是O(1)。

C++程式碼:

#include<iostream>
#include<string>
#include<cmath>

using namespace std;

int main() {
	string input;
	cin >> input;
	int result = 0;
	for(int i = 0; i < input.length(); i++) {
		if(i == 0) {
			if(input[i] == '1') {
				int right = 0;
				for(int j = 1; j < input.length(); j++) {
					right = right * 10 + input[j] - '0';
				}
				result += right + 1;
			} else {
				result += (int)pow(10, input.length() - 1);
			}
		} else if(i == input.length() - 1) {
			int left = 0;
			for(int j = 0; j < input.length() - 1; j++) {
				left = left * 10 + input[j] - '0';
			}
			result += left + 1;
			if(input[i] == '0') {
				result--;
			}
		} else {
			int left = 0, right = 0;
			for(int j = 0; j < i; j++){
				left = left * 10 + input[j] - '0';
			}
			for(int j = i + 1; j < input.length(); j++){
				right = right * 10 + input[j] - '0';
			}
			if(input[i] == '0'){
				result += left * (int)pow(10, input.length() - i - 1);
			}else if(input[i] == '1'){
				result += left * (int)pow(10, input.length() - i - 1) + right + 1;
			}else{
				result += (left + 1) * (int)pow(10, input.length() - i - 1);
			}
		}
	}
	printf("%d\n", result);
	return 0;
}

C++解題報告: