演算法設計之補零遞迴法(統計數字問題)
問題:給定一個數N求從1到N的這N個數中0,1,2,3,4,5,6,7,8,9這10個數字出現的次數。注意,所有的數字沒有前導的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的次數,即:從0到ABCDE的數中,有多少個數的百位上是2。分析完它,就可以用同樣的方法去計算個位,十位,千位,萬位等各個位上出現2的次數。
第一種情況:當百位上的數C小於2時:1)當百位c為0時,比如說12013,0到12013中哪些數的百位會出現2?我們從小的數起,
200~299, 1200~1299, 2200~2299, … , 11200~11299,
也就是固定低3位為200~299,然後高位依次從0到11,共12個。再往下12200~12299
已經大於12013,因此不再往下。所以,當百位為0時,百位出現2的次數只由更高位決定,等於更高位數字
第二種情況:當百位上的數C等於2時:當百位C為2時,比如說12213。那麼,我們還是有200~299,
1200~1299, 2200~2299, … , 11200~11299這1200個數,他們的百位為2。但同時,還有一部分12200~12213,共14個(低位數字+1)。所以,當百位數字為2時,百位出現2的次數既受高位影響也受低位影響,結論如下:
當百位C大於2時,比如說12313,那麼固定低3位為200~299,高位依次可以從0到12,這一次就把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]);
}
}
}
}