1. 程式人生 > >求小於等於N的所有正整數裡面包含的1的個數

求小於等於N的所有正整數裡面包含的1的個數

題目:

已知一個正整數N,求比N小(包括N)的所有正整數中包含的1的個數。例如N = 12,則包含5個1,分別為1、10、11、12

解答:

  1. 最直觀最簡單的想法是,從1到N對每一個數檢查,得出每個數中包含的一的個數,事件複雜度大概是O(N)
  2. 1時間複雜度比較高,不是最優演算法。一個比1快的演算法是:對N的每一位進行檢查,得出比N小的正數某一位包含的1的個數總和。比如1234,千位包含234 + 1個1(1000 ~ 1234),百位包含 2 * 100個1(1100 ~ 1199, 100 ~ 199),十位包含13 * 10個1(1210 ~ 1219,1110 ~ 1119,。。。。。。,10 ~ 19),個位包含124 * 1個1(1231,1221,1211,1201,。。。。。。,1)。按照這個思路可以寫出程式碼如下。

程式碼:

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

int getNumAfterI(char *buf, int i, int len)
{
	int sum = 0;
	for(int j = i + 1; j < len; j++)
		sum = sum * 10 + (buf[j] - '0');
	return sum + 1;
}

int NumOf1AfterN(int n)
{
	int sum = 0;
	int num = 0;
	char buf[20];
	sprintf(buf, "%d", n);
	int len = strlen(buf);

	for(int i = 0; i < len; i++)
	{
		if(buf[i] > '1')
			sum += (num + 1) * pow(10, len - i - 1);
		else if(buf[i] == '0')
			sum += num * pow(10, len - i - 1);
		else
			sum += (num + 1) * getNumAfterI(buf, i, len);
		num = num * 10 + (buf[i] - '0');
	}
	return sum;
}

//test
int main()
{
	int num;
	while(1)
	{
		cin >> num;
		cout << NumOf1AfterN(num) << endl;
	}
	
	return 0;
}