1. 程式人生 > >【劍指offer】整數中1出現的次數

【劍指offer】整數中1出現的次數

題目描述:

親們!!我們的外國友人YZ這幾天總是睡不好,初中奧數裡有一個題目一直困擾著他,特此他向JOBDU發來求助信,希望親們能幫幫他。問題是:求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有110111213因此共出現6,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。

輸入:

輸入有多組資料,每組測試資料為一行。

每一行有兩個整數a,b(0<=a,b<=1,000,000,000)

輸出:

對應每個測試案例,輸出ab之間1出現的次數。

樣例輸入:
0 5
1 13
21 55
31 99
樣例輸出:
1
6
4
7
   思路:我們先寫一個函式,求出從1到整數n之間1出現的次數,而後分別將要求輸入的兩個數(具體說,應該是最大的數,和最小的數減去1)作為引數傳入該函式,得到的值相減,即可得到二者之間的的數中1出現的次數

    最簡單的方法,分別求從1到n之間每個數中的1的個數,由於整數n的位數為O(logn),我們要判斷一個數有多少個1,需要判斷其每一位是否為1,這樣一個數就需要判斷O(logn)次,而總共有n個數需要求,那麼該方法的時間複雜度為O(nlogn)。在九度OJ上用該方法寫的程式碼測試,會超時。

    劍指offer上給了一種遞迴的思路,能將時間複雜度降到O(logn),總感覺這個思路有點偏,而且很難想到,我沒仔細看。我的想法是各位分開統計,而且看到何海濤部落格下面很多人留言,也用了這樣的方法,就看了下詳細的思路,並自己推導了下公式,寫出了程式碼,感覺這種方法還是很nice的,直觀易懂,而且程式碼簡潔,時間複雜度同為O(logn)。

    這種方法的思路大概是這樣的(懶得動手打了,直接copy):

    按每一位來考慮,

    1)此位大於1,這一位上1的個數有 ([n / 10^(b+1) ] + 1) * 10^b
    2)此位等於0,為 ([n / 10^(b+1) ] ) * 10^b
    3)此位等於1,在0的基礎上加上n mod 10^b + 1

    舉個例子:

    30143:    由於3>1,則個位上出現1的次數為(3014+1)*1    由於4>1,則十位上出現1的次數為(301+1)*10    由於1=1,則百位上出現1次數為(30+0)*100+(43+1)    由於0<1,則千位上出現1次數為(3+0)*1000    注:以百位為例,百位出現1為100~199,*100的意思為單步出現了100~199,100次,*30是因為出現了30次100~199,+(43+1)是因為左後一次301**不完整導致。    如果還不懂,自己拿紙和筆大致寫下,找下規律,就能推匯出來了!    兩外,需要注意一點:由於測試系統要求的輸入資料最大為1,000,000,000,因此用int會溢位,要用long long,另外比較坑跌的一點是a可能比b大,居然都沒有說明,有點坑了。
    AC程式碼如下:
#include<stdio.h>

/*
分別統計num各位上1出現的次數,
相加得到1出現的總次數
*/
long long CountNum1(long long num)
{
	if(num <= 0)
		return 0;

	long long count = 0;	//統計1出現的次數
	long long current;    //當前位
	long long base = 1;	//當前位的基
	long long remain = 0;	//當前位為1時,後面位剩餘的數(即不完整的部分)中1出現的次數
	while(num)
	{
		current = num%10;
		num = num/10;

		if(current > 1)
			 count += (num+1)*base;
		else if(current == 1)
			count += num*base + (remain+1);
		else
			count += num*base;
	
		//下一位要用到的基和剩餘不完整部分值
		remain += current*base; 
		base *= 10;
	}

	return count;
}

int main()
{
	long long a,b;
	//a,b的大小不定
	while(scanf("%lld %lld",&a,&b) != EOF)
	{
		long long result;
		if(a > b)
			result = CountNum1(a) - CountNum1(b-1);
		else
			result = CountNum1(b) - CountNum1(a-1);

		printf("%lld\n",result);
	}
	return 0;
}
/**************************************************************Problem: 1373User: mmc_maodunLanguage: CResult: AcceptedTime:0 msMemory:912 kb****************************************************************/

相關推薦

offer整數1出現次數(從1到n整數1出現次數

題目描述 求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數(從1

offer整數1出現次數

題目描述:親們!!我們的外國友人YZ這幾天總是睡不好,初中奧數裡有一個題目一直困擾著他,特此他向JOBDU發來求助信,希望親們能幫幫他。問題是:求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、1

offer二進位制1的個數(java)

問題描述:輸入一個二進位制數,我們記為num,計算出num中有幾個1,結果用count儲存 思路分析:如二進位制數11011,將其減1,得11010,再與原來的數做與運算 11011&11010,得11010,此二進位制數相比原二進位制數,數中的1少了一個。重複此過程,直至該數變為0

Offer二進位制1的個數

題目描述 輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。 補碼 解題前,我們先來了解一下補碼。在計算機系統中,數值都是用補碼來表示和儲存的。 而原碼就是數值的二進位制數表示,最高位1表示負數。 以32位數值舉例 1的原碼就是 -1的原碼就是 正數的補碼等於原碼 負數的補碼等於其原碼

offer整數1出現次數

題目描述 求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區

offer陣列出現一次的數字

remove:刪除特定元素第一次出現的時候,返回的是刪除後的陣列 del:刪除指定索引的元素 del a[2],返回的是刪除後的陣列 pop:刪除指定索引的元素,返回的是刪除的元素 有一個問題就是我不知道判斷not in list 的時候O(n)的複雜度會不會影響 執

[offer] 31. 整數1出現次數(從1到n整數1出現次數

題目描述 求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數(從1

offer整數1出現次數(python)

求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。

offer——31.整數1出現次數

題目描述 求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出

offer整數1出現次數(從1到n整數1出現次數)(Python)

題目描述 求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出

offer--32.整數1出現次數(從1到n整數1出現次數

public return between acm span class turn style ++ 暴力挨個數 ---------------------------------------------------------------------- 時間限制:1秒

offer43、1~n整數1出現次數

ase 表示 eight pre pub 題目 我們 return 1出現的次數 題目 輸入一個整數,求1~n的整數十進制表示中1出現的次數。如12,有1,10,11,12,總共出現了5次。 思路 註意不是統計出現1的數字的多少,而是統計1出現了幾次。 我們按位來分析 個位

offer無聊的1+2+...+n

乘除 detail lin targe while http off 技術分享 i++ 轉載請註明出處:http://blog.csdn.net/ns_code/article/details/27964027題目描寫敘述:求1+2+3+...+n,要求不能使用乘除法、f

offer圓圈最後剩下的數字,C++實現

一行 AC 個人 ron namespace itl i++ float color 原創博文,轉載請註明出處! # 題目 # 思路 本題即為典型的約瑟夫問題,通過遞推公式解決。 第一行表示每個人的下標,現在要從11個人中刪除報數為3的人,從圖

offer序列的某一位數字

題目描述 數字以01234567891011121314…的格式序列化到一個字元序列中,在這個序列中,從0開始數,第5位是5,第13位是1,第19位是4,等等,請寫一個函式,求任意第n位對應的數字。 求出每一位對應的數字總和,然後判斷。注意邊界條件不好處理時,可以採用while true

offer陣列的逆序對(校正書上錯誤)歸併排序

題目描述 在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個陣列中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007 題目保證輸入的陣列中沒有的相同的數字 資料範圍:

Offer陣列重複的數字

題目連結 題目描述 在一個長度為n的數組裡的所有數字都在0到n-1的範圍內。 陣列中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出陣列中任意一個重複的數字。 例如,如

offer矩陣的路徑(回溯法)

# -*- coding:utf-8 -*- class Solution: def hasPathCore(self, matrix, rows, cols, row, col, path,

offer陣列出現次數超過陣列長度一半的數字(三種解法)

題目描述 陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。如果不存在則輸出0。 如果使用時間複雜度為O(n),可以構建

Offer第一個只出現一次的字元

題目連結 題目描述 在一個字串(0<=字串長度<=10000,全部由字母組成)中找到第一個只出現一次的字元,並返回它的位置, 如果沒有則返回 -1(需要區分大小寫). 分析:簡單計數並