1. 程式人生 > >LeetCode第233題數字1的個數

LeetCode第233題數字1的個數

原題如下:

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

示例:

輸入: 13
輸出: 6
解釋: 數字 1 出現在以下數字中: 1, 10, 11, 12, 13 。

思路如下:

0.暴力破解法,依次遍歷每個數中的1的個數,累加起來(演算法題如果是挨個寫到這題的話,這個想法在腦中也就是一閃而過)
1.遞迴法:
為了方便操作做了一些前導操作:把一個int拆分成vector,同時也寫了一個vector轉回int的函式
對於vector<int>nums 的i號元素(即原數的第i+1位)而言分為3種情況:
0)nums【i】==0;直接digui下一位;
1)nums【i】==1;比如說nums【i----nums.size()-1】所構成的數是185那麼他產生的1的總共個數有以下幾個部分
(185是3位數)所以第一部分(數字低於3位,,1位or2位)他至少包括2個數所構成的最大1的個數(其實就0-99之間1的個數和ps:這個是完全2位數構成的)第二部分(數字必須是3位數(100-185))我們會發現首位是1,至少包括

185-100+1個(但是這只是第一個位置上的1的個數,後面還有2位呢),所以再加上85所能得到1的個數(digui(85))

即最終結果為::m【2】+(185-100+1)+digui(85)

2)nums【i】>=2;
這裡拿485舉例:==第一部分(數字低於3位,,1位or2位)==這個和上面的情況一樣;第二部分(數字必須是3位數)
以1打頭;這時候情況跟上面不太一樣,因為我們可以達到199!!!,所以以1打頭的為(199-100+1)+digui(99),ps:digui(99)其實就是完全2位數構成的1個數記為m【2】,即為:(199-100+1)+m【2】;
以2,3打頭是可以達到,299,399的(所以和4不一樣)
他們每個都是完全2位構成1的個數即2個*m【2】;
以4打頭的(400-485):這時候我們不能把他記為m【2】(digui(99)),應該單算一下digui(85);

即最終答案為:(199-100+1)+m【2】+2個*m【2】+digui(85);不把m【2】合併是為了方便理解

程式碼如下:

vector<int> makeDigitVector(int &n){
		vector<int>m;
		if (n <= 9)return{ n };
		while (n){
			int t = n % 10;
			vector<int>::iterator p = m.begin();
			m.insert(p,t);
			n /= 10;
		}
		return m;
	}
	int canGetMAX(int size ,vector<int>&m){
		int total=0;
		if (size == 1){ m[1] = 1; return 1; }
		int x = canGetMAX(size - 1,m);
		total = pow(10, size - 1)+10*x;
		m[size] = total;
		return total;
	}
	int vectorToInt(vector<int>&nums, int & begin){
		int total=0;
		for (int i = begin; i <= nums.size() - 1; i++)
			total += nums[i] * pow(10, nums.size() - 1 - i);
		return total;
	}
	int digui(vector<int>&nums,int begin,vector<int>&m){
		int total = 0;
		if (begin == nums.size() - 1) {
			if (nums[begin] == 0)return 0;
			else return 1;
		}
		if (nums[begin] == 0)return digui(nums, begin + 1, m);
		else if (nums[begin] == 1){
			int now_size = nums.size() - begin;
			int x = vectorToInt(nums, begin);
			int y = pow(10, now_size - 1);
			total = x - y + 1 + digui(nums, begin + 1, m) + m[now_size - 1];
			return total;
		}
		else{
			int now_size = nums.size() - begin;
			int z = pow(10, now_size - 1)+m[now_size-1];
			int x = (nums[begin] - 2)*m[now_size-1];
			total = z + x + digui(nums, begin + 1, m) + m[now_size - 1];
			return total;
		}
	}
	int countDigitOne(int n) {
		if (n <= 9){
			if (n <= 0)return 0;
			else return 1;
		}
		vector<int>nums=makeDigitVector(n);
		vector<int>m(nums.size()+1, 0);
		canGetMAX(nums.size() , m);
		return digui(nums, 0, m);
	}