1. 程式人生 > >演算法設計之補零遞迴法(統計數字問題)

演算法設計之補零遞迴法(統計數字問題)

問題:給定一個數N求從1N的這N個數中0,1,2,3,4,5,6,7,8,910個數字出現的次數。注意,所有的數字沒有前導的0。 如6要寫成6,而不是 006 06這種形式

思路1:也就是最簡單最容易實現的做法,但是當n很大的時候,執行時間會變得十分長

import java.util.Scanner;

public class CountPage {
	private static Scanner scanner;

	public static void main(String[] args) {
		scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			int n = scanner.nextInt();
			int j;
			int pageNum[] = new int[10];// 存放0--9的個數
			for (int i = 1; i <= n; i++) {
				int k = i;
				while (k != 0) {
					j = k % 10;
					k = k / 10;
					pageNum[j]++;
				}
			}
			 for(int i = 0;i< 10;i++)
		        {
				 	System.out.println(i+"--"+pageNum[i]);
		        }
		}
	}
}


思路2:這個思路是來自《程式設計之美》的

假設有一個5位數N=ABCDE,我們現在來考慮百位上出現2的次數,即:從0ABCDE的數中,有多少個數的百位上是2。分析完它,就可以用同樣的方法去計算個位,十位,千位,萬位等各個位上出現2的次數。

第一種情況:當百位上的數C小於2時:1)當百位c0時,比如說12013012013中哪些數的百位會出現2?我們從小的數起, 200~299, 1200~1299, 2200~2299, … , 11200~11299, 也就是固定低3位為200~299,然後高位依次從011,共12個。再往下12200~12299 已經大於12013,因此不再往下。所以,當百位為0時,百位出現2的次數只由更高位決定,等於更高位數字

(12)x當前位數(100)=1200個。2)當百位C1時,比如說12113。分析同上,並且和上面的情況一模一樣。最大也只能到11200~11299,所以百位出現2的次數也是1200個。上面兩步綜合起來,可以得到以下結論:—>當某一位的數字小於2時,那麼該位出現2的次數為:更高位數字x當前位數

第二種情況:當百位上的數C等於2時:當百位C2時,比如說12213。那麼,我們還是有200~299, 1200~1299, 2200~2299, … , 11200~112991200個數,他們的百位為2。但同時,還有一部分12200~12213,共14(低位數字+1)。所以,當百位數字為2時,百位出現2的次數既受高位影響也受低位影響,結論如下:

—>當某一位的數字等於2時,那麼該位出現2的次數為:更高位數字x當前位數+低位數字+1第三種情況:當百位上的數C大於2時:

當百位C大於2時,比如說12313,那麼固定低3位為200~299,高位依次可以從012,這一次就把12200~12299也包含了,同時也沒低位什麼事情。因此出現2的次數是: (更高位數字+1)x當前位數。結論如下:—>當某一位的數字大於2時,那麼該位出現2的次數為:(更高位數字+1)x當前位數通過上述分析,我們可以得到以下規律:(1)當某一位的數字小於i時,那麼該位出現i的次數為:更高位數字x當前位數(2)當某一位的數字等於i時,那麼該位出現i的次數為:更高位數字x當前位數+低位數字+1(3)當某一位的數字大於i時,那麼該位出現i的次數為:(更高位數字+1)x當前位數

下面使用java實現該演算法:

import java.util.Scanner;

public class CountPagePro {
	private static Scanner scanner;

	public static void main(String[] args) {
		scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			int n = scanner.nextInt();
			int[] pageNum = new int[10];
			int a = 1;
			int zero = 0;
			int place = 0;// 位數
			while (n / a != 0) {
				int lowPo = a - (a / n) * n;
				int curre = (a / (n)) % 10;
				int highPo = a / (n * 10);
				place++;
				for (int i = 0; i < 10; i++) {
					if (i < curre) {
						pageNum[i] += (highPo + 1) * n;
					} else if (i == curre) {
						pageNum[i] += (highPo) * n;
						pageNum[i] += (lowPo + 1);

					} else {
						pageNum[i] += (highPo) * n;
					}
				}
				n = n * 10;
			}
			int t = 1;
			while (t <= place) {
				n = n / 10;
				zero += t * (n - 1 - n / 10 + 1);
				t++;
			}
			pageNum[0] = pageNum[0] - zero;
			for (int i : pageNum) {
				System.out.println(i + "--" + pageNum[i]);
			}
		}
	}
}