找出"吸血鬼数"(Java)

吸血鬼数是指位数为偶数的数字,可以由一 对数字相乘而得到,而这对数字各包含乘积的一半 位数的数字,其中从最初的数字中选取的数字可以任意排序。以两个0结尾的数字是不允许的,例如,下列数字都是 “吸血鬼”数字:
1260=21 * 60
1827=21 * 87
2187= 27 * 81

那么,开始

由于判断四位数是否能分解为两个两位数的乘积,比判断两位数的乘积所得四位数的,要麻烦得多,因此思路为后者。

import java.util.ArrayList;
import java.util.Arrays;

/**
 *     先从1001开始到9999开始判断,是否能分解为两个二位数,如果可以,二维数是否包含所有四个数字
 *     把四位数分解成二位数乘积过于麻烦,而且一个四位数可能存在多种分解方式,加大了设计的难度
 *     但是反过来,二位数乘以二位数简单得多,此时再去判断即可
 *     将积分解成四个数位,存入数组。两个乘数分别分解成两个数位,存入一个数组
 *     将两个数组排序,按照下标逐个比较,如果两个数组相同,返回true
 * @author zhaoke
 *
 */
public class Vampire {

    //冒泡排序法
    public void sort(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i] > array[j]) {
                    //交换两个数的位置
                    array[i] = array[i] - array[j];
                    array[j] = array[i] + array[j];
                    array[i] = array[j] - array[i];
                }
            }
        }
    }
    
    /**
     * 判断四位数分解后的数位(存在数组里),是否恰好包含两个乘积因子的所有数位
     * 为了简单起见,方法是先排序,然后比较两个数组是否相同
     */
    public boolean check(int[] digits, int num1, int num2) {
        this.sort(digits);
//        System.out.println(Arrays.toString(digits));
        
        int[] factors = new int[4];
        //分离第一个乘数的两个数位
        int[] numArray = this.divideNumber(num1);
        for (int i = 0; i < 2; i++) {
            factors[i] = numArray[i];
        }
        //分离第二个乘数的两个数位
        numArray = this.divideNumber(num2);
        for (int i = 2; i < 4; i++) {
            factors[i] = numArray[i-2];
        }
        this.sort(factors);
//        System.out.println(Arrays.toString(factors));
        for (int i = 0; i < digits.length; i++) {
            if (digits[i] != factors[i]) {
                return false;
            }
        }
        return true;
    }
    
    public int[] divideNumber(int number) {
        int[] digits = new int[2];
        digits[0] = number/10;
        digits[1] = number - 10*(number/10);
        return digits;
    }
    
    /**
     * 获得每个位的数字
     */
    public int[] divideArray(int number) {
        int[] digits = new int[4];
        int factor = 1000;
        for (int i = 0; i < digits.length; i++) {
            digits[i] = number/factor;
            number -= digits[i] * factor;
            factor /= 10;
        }
        return digits;
    }
    ArrayList<Integer> result = new ArrayList<Integer>();

    /**
     * 10*99小于1000,因此从11开始循环
     */
    public void start() {
        int count = 0; //计数器而已
        for (int i = 11; i < 100; i++) {
            for (int j = 11; j < 100; j++) {
                if (i*j <1000)
                    continue;
                if (i*j%100==0) {
                    //根据题目,如果最后两位是0,也不可
                    continue;
                }
                int[] digits = divideArray(i*j);
                if (this.check(digits, i, j)) {
                    if (this.result.contains(i*j))
                        continue;
                    this.result.add(i*j);
                    System.out.printf("第%d个吸血鬼数: %d = %d x %d \n",++count,i*j,i,j);
                }
            }
        }
    }
    
    public static void main(String[] args) {
        Vampire v = new Vampire();
        v.start();
    }

}

结果如下:

第1个吸血鬼数: 1395 = 15 x 93 
第2个吸血鬼数: 1260 = 21 x 60 
第3个吸血鬼数: 1827 = 21 x 87 
第4个吸血鬼数: 2187 = 27 x 81 
第5个吸血鬼数: 1530 = 30 x 51 
第6个吸血鬼数: 1435 = 35 x 41 
第7个吸血鬼数: 6880 = 80 x 86 

总结:逆向思维,模块化设计

posted @ 2020-03-27 14:03  倦鸟已归时  阅读(374)  评论(0编辑  收藏  举报