java編程——吸血鬼數字(四位)

從《Thinking in Java》(中文第四版)中第4章的練習10看到“吸血鬼數字”,特編程實現,以下爲3種算法(針對四位數的)及其對比:

首先解釋一下吸血鬼數字:吸血鬼數字是指位數爲偶數的數字,可由一對數字相乘而得到,這對數字各包含乘積的一半位數的數字,以兩個0結尾的數字是不允許的。

 四位數吸血鬼數字示例:1260=21*60,1827=21*87,2187=27*81……

先列出結果:一共7個:1260=21*60,1395=15*93,1435=41*35,1530=51*30,1827=87*21,2187=27*81,6880=86*80


方法一:

本方法是《Thinking in Java》的官方答案,由於所處章節很靠前,所以採用的遍歷四位數方法,正向思維,即先有四位數,再拆分,四個數字組合相乘,若乘積與原數相等,則輸出,並計算爲一個吸血鬼數字。

public class SearchforVampireThinkinginJava {

	// control/VampireNumbers.java
	// TIJ4 Chapter Control, Exercise 10, page 154
	/* A vampire number has an even number of digits and is formed by multiplying a
	* pair of numbers containing half the number of digits of the result. The
	* digits are taken from the original number in any order. Pairs of trailing
	* zeroes are not allowed. Examples include: 1260 = 21 * 60, 1827 = 21 * 87,
	* 2187 = 27  * 81. Write a program that finds all the 4-digit vampire numbers.
	* (Suggested by Dan Forhan.)
	*/ 
//	本方法是順向思維,即先有四位數,再拆分,四個數字組合相乘,若乘積與原數相等,則輸出,並計算爲一個吸血鬼數字。TMJG添加此行並註釋
//	其實sum的結果爲107976次,非常大,算法效率很低,並且出現了重複(6880 = 86 * 80,6880 = 80 * 86)。TMJG添加此行並註釋
	
			static int sum=0;//記錄調用判斷的次數,TMJG添加此行並註釋
			static int a(int i) {
				return i/1000;    //求千位數字,下同,TMJG添加此行並註釋
			}
			static int b(int i) {
				return (i%1000)/100;
			}
			static int c(int i) {
				return ((i%1000)%100)/10;
			}
			static int d(int i) {
				return ((i%1000)%100)%10;
			}
			static int com(int i, int j) {   //形成10~99的兩位數,TMJG添加此行並註釋
				return (i * 10) + j;
			}
			static void productTest (int i, int m, int n) {
				sum++;
				if(m * n == i) System.out.println(i + " = " + m + " * " + n);
			}	
		public static void main(String[] args) {		
			for(int i = 1001; i < 9999; i++) {			
				productTest(i, com(a(i), b(i)), com(c(i), d(i)));
				productTest(i, com(a(i), b(i)), com(d(i), c(i)));
				productTest(i, com(a(i), c(i)), com(b(i), d(i)));
				productTest(i, com(a(i), c(i)), com(d(i), b(i)));
				productTest(i, com(a(i), d(i)), com(b(i), c(i)));
				productTest(i, com(a(i), d(i)), com(c(i), b(i)));
				productTest(i, com(b(i), a(i)), com(c(i), d(i)));
				productTest(i, com(b(i), a(i)), com(d(i), c(i)));
				productTest(i, com(b(i), c(i)), com(d(i), a(i)));
				productTest(i, com(b(i), d(i)), com(c(i), a(i)));
				productTest(i, com(c(i), a(i)), com(d(i), b(i)));
				productTest(i, com(c(i), b(i)), com(d(i), a(i)));
			}	
			System.out.println("總共調用判斷的次數爲:"+sum);//TMJG添加此行並註釋
		} 
}

方法二:

本方法是對方法一的改進,跳過了一些數字(如1100這樣末尾兩個0的,如1010、1001這樣明顯不可能是吸血鬼數字的數字),並且避免了出現重複的可能性,但是效率仍然很低,需要判斷104942次。

public class SearchforVampireNumbersLJ {
	public static int count = 0;// 記錄一共有多少個吸血鬼數字
	public static int k=0;//記錄調用判斷多少次
	public static void main(String[] args) {
		for (int i = 1001; i < 10000; i++) {
			// 如果數字是像1100這種末尾至少有2個0的,則跳過
			if (i % 100 == 0) {
				continue;
			}
			// 獲得數字四個數值位上的數字,這裏我們假定四位數表示爲abcd
			int a = i / 1000;
			int b = (i - a * 1000) / 100;
			int c = (i - a * 1000 - b * 100) / 10;
			int d = i - a * 1000 - b * 100 - c * 10;
			// 判斷四個位置上是否有兩個0存在的情況,如1010,並跳過這些數,由於千位不可能爲0,因此只需要判斷另外三位是否有2個0的情況
			// 當3個數中有2個0時,必然存在“3個數之和等於其中某一個數”,以此作爲判斷依據,而後兩位爲0的也已經排除,其實只需要判斷如1001,和1010這種情況即可
			if (b + c + d == c || b + c + d == d) {
				continue;
			}
			// 排除掉各種情況後,可以開始真正的吸血鬼數字篩選了
			// 那麼一共有12種情況:abcd,abdc,acbd,acdb,adbc,adcb,bacd,badc,bcda,bdca,cadb,cbda
			if (search(i, a, b, c, d)) {
			} else if (search(i, a, b, d, c)) {
			} else if (search(i, a, c, b, d)) {
			} else if (search(i, a, c, d, b)) {
			} else if (search(i, a, d, b, c)) {
			} else if (search(i, a, d, c, b)) {
			} else if (search(i, b, a, c, d)) {
			} else if (search(i, b, a, d, c)) {
			} else if (search(i, b, c, d, a)) {
			} else if (search(i, b, d, c, a)) {
			} else if (search(i, c, a, d, b)) {
			} else if (search(i, c, b, d, a)) {
			}
		}
		System.out.println("四位數的吸血鬼數字一共有" + count + "個。");
		System.out.println("一共調用判斷次數爲" + k);
	}

	//判斷是否滿足條件
	static  boolean search(int i, int a, int b, int c, int d) {
		k++;
		if ((a * 10 + b) * (c * 10 + d) == i) {
			searchfor(i,a,b,c,d);//如果滿足條件,則打印結果
			return true;
		}else{
			return false;
		}
	}

	//滿足條件即打印,並且統計個數
	static void searchfor(int i, int a, int b, int c, int d) {
		count++;
		System.out.println(i + "=" + (a * 10 + b) + "*" + (c * 10 + d));
	}
}

方法三:

以下是網上找的代碼,該算法採用逆向思維,4位數字的吸血鬼數字只能拆分成兩個2位數,因此遍歷所有兩個兩位數相乘的情況,除去不符合的情況不用判斷,其他挨個判斷即可。

public class SearchforVampireFromInternet {
	    /**   
	     * 代碼來自網絡,略作修改並添加了註釋
	     * 該算法只需要執行3721次
	     */   
	    public static void main(String[] args) {   
	        String[] targetNum = null;
	        String[] gunNum=null;   //目標數字和槍數字(即對比數字)
	        int sum = 0;   //吸血鬼數字的總個數
	        int count=0;   //有效判斷次數,那些乘積不是4位數的就排除了
	        for (int i = 10; i < 100; i++) {   
	            for (int j = i+1; j < 100; j++) {   //沒有哪個兩位數滿足ab*ab=abab(不信可以編程驗證),所以這裏j從i+1開始就可以了
	                int i_target = i * j;   
	                if (i_target < 1000 || i_target > 9999)   
	                    continue; // 積不是4位數則跳過 
	                count++;
	                targetNum = String.valueOf(i_target).split("");  //將其轉換爲一個字符串數組
	                gunNum = (String.valueOf(i) + String.valueOf(j)).split("");   
	                java.util.Arrays.sort(targetNum);   //升序排列,因爲只有排列了再比較才能保證不遺漏abcd=ba*dc這樣的情況
	                java.util.Arrays.sort(gunNum);   
	                if (java.util.Arrays.equals(targetNum, gunNum)) {   
	                    // 排序後比較,爲真則找到一組   
	                    sum++;   
	                    System.out.println("第" + sum + "個: " +  i_target+"="+i + "*" + j);   
	                }   
	            }   
	        }   
	        System.out.println("共進行了"+count+"次判斷,找到" + sum + "個吸血鬼數字。");
	    }   
}



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