給定一個十進制正整數N,寫下從1開始,到N的所有整數,然後數一下其中出現的所有1的個數

這個是《編程之美》上的一個題目,題目如題:

給定一個十進制正整數N,寫下從1開始,到N的所有整數,然後數一下其中出現的所有1的個數。

書上給出了兩個解法,第一個就是笨方法,挨個數唄,最後加一塊。

第二個解法,有興趣的自己看書上的分析吧,這裏先把Java實現的代碼貼下:

public static long F_Sum1s(long n){
		long iCount = 0;
		long iFactor = 1;
		long iLowerNum = 0;
		long iCurrNum = 0;
		long iHigherNum = 0;
		
		while(n/iFactor != 0){
			iLowerNum = n - (n/iFactor)*iFactor;
			iCurrNum = (n/iFactor)%10;
			iHigherNum=n/(iFactor*10);
			
			switch(String.valueOf(iCurrNum)){
			case "0":
				iCount += iHigherNum*iFactor;
				break;
			case "1":
				iCount += iHigherNum*iFactor+iLowerNum+1;
				break;
			default:
				iCount += (iHigherNum+1)*iFactor;
				break;
			}
			iFactor *= 10;
		}
		return iCount;
	}


之前我想到一個遞推公式,想來和書上的解法本質應該差不多,現把公式和代碼貼出來供大家討論下,是否正確(自己簡單試了下,12位以下的數字,和書上的結果一樣,但沒嚴格證明過)。

實際求的時候,先計算該數長度,然後判斷Gn存在否,不存在,就求出之,最後遞推求出結果,代碼如下:

package algorithm;

public class Sum1s {
	
	public static long F_Sum1s(long n){ //上面已貼出}
	int[] GArr = new int[100];  //存放G的數組
	int GArrIndex = 0;
	public Sum1s(){
		GArr[0]=0; GArr[1]=0; GArr[2]=1;
		GArrIndex = 2;
	}

	public long My_Sum1s(long n){   //計算的函數
 		if(n == 0){
			return 0;
		}
		int numLength = 1;
		long tempNum = n;
		int An = 0;
		while(tempNum/10 != 0){
			numLength += 1;
			tempNum = tempNum/10;
		}
		An = (int)tempNum;
		//System.out.println("NumLength = "+numLength);
		
		if(numLength == 1){
			return 1;
		}
		
		if(numLength > GArrIndex){
			InitGArr(numLength);
		}
		
		long numLength_1_10 = 1;
		for(int i=1; i<numLength; i++){
			numLength_1_10 *= 10;
		}
		long Vn_1 = n-An*numLength_1_10;
		if(An == 1){
			return GArr[numLength]+1+Vn_1+My_Sum1s(Vn_1);
		}else{
			return (An*GArr[numLength]+numLength_1_10)+My_Sum1s(Vn_1);
		}
	}
	
	public void InitGArr(long numLength){
		long numLength_1_10 = 1;
		for(int i=1; i<GArrIndex; i++){
			numLength_1_10 *= 10;
		}
		for(++GArrIndex;GArrIndex<=numLength;GArrIndex++){
			numLength_1_10 *= 10;
			GArr[GArrIndex] = (int)My_Sum1s(numLength_1_10-1);
		}
		GArrIndex--;
	}
	
	public static void main(String args[]){
 		//System.out.println(Sum1s.F_Sum1s(1999));
		Sum1s sum1s = new Sum1s();
		//long sum1,sum2;
		//int i=999;
		//while(true){
		//	sum1 = Sum1s.F_Sum1s(i);
		//	sum2 = sum1s.My_Sum1s(i);
		//	System.out.println(i);
		//	if(sum1 != sum2){
		//		System.out.println("sum1="+sum1+",sum2="+sum2);
		//		break;
		//	}
		//	i++;
		//}
		System.out.println(sum1s.My_Sum1s(1000));
	}
}


 接着看《編程之美》發現求Gn有個歸納出的公式

             9:                                                          1個

           99:                                                        20個

          999:                                                     300個

        9999:                                                   4000個

                  。。。

   999 999 999:                                 900 000 000個

9 999 999 999:                            10 000 000 000個

f(10^n -1) = n*10^(10-1)。那麼前面Gn的地方就簡單了。直接帶入公式,當然10的冪沒必要從頭計算。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章