吸血鬼数字

题目

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

分析

这个问题是《Java编程思想》第四章最后的一道练习题,主要是为了练习各种循环控制语句的用法。上网搜了一下答案,很暴力,直接穷举了出来。这个题目考察的核心其实是全排列问题,只要在遍历四位数的时候,能够将他的所有组合穷举出来,然后再进行两两拆分,条件判断即可。其实还可以根据筛选条件,优化一下穷举范围,但我懒了,我有罪,我反思。

全排列逻辑

根据题目要求,要将每个四位数拆成两个两位数,并且其相乘结果还是等于这个数本身。为了不重不漏,需要将这个四位数进行一次全排列,即每个数会有 A 4 4 = 24 A^4_4=24 种可能,将这24种可能按前二后二进行拆分,然后根据不能全为0结尾以及乘积等于自身作为筛选条件进行过滤。

那么全排列该如何完成呢?这是一种分治的思想,4个数的全排列可以拆解成4组3个数的全排列,以此类推,最终拆解到只剩一个数,那这个数就是全排列的,可以直接返回。从上述描述中不难看出,这个全排列的过程是一个递归的过程,其递归结束条件为全排列的首和尾脚标相等,即只剩一个数字。

我们将每次拆解的第一个数字保持不动,全排列后面的数字。
如1234,我们先拆成1234,2134,3213,4231四个数字,再进行后面3个数字全排序。
即将第一位数字与后面的数字逐一进行调换(swap),后对剩余数字进行全排列(fullSort),为了保证一次排序结果不影响下一次排序结果我们需要在一次全排列后进行恢复,即第二个swap。

private static void fullSort(int[] arr, int start, int end, List<String> result) {
    if (start == end) {
        StringBuilder sb = new StringBuilder();
        for (int i : arr) {
            sb.append(i);
        }
        result.add(sb.toString());
        return;
    }
    for (int i = start; i <= end; i++) {
        swap(arr, i, start);
        fullSort(arr, start + 1, end, result);
        swap(arr, i, start);
    }
}

private static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

判断逻辑

解决了全排序后,只需要对返回的字符串集进行遍历,拆分以及筛选既可以得到最终结果,这个逻辑很简单,不废话了直接上代码。

// 遍历&拆分代码
for (String s : numbers) {
    if (isVampireNumber(i, s)) {
        System.out.println(i + "=" + s.substring(0, 2) + "*" + s.substring(2));
        break;
    }
}
// 筛选逻辑
private static boolean isVampireNumber(int ori, String num) {
    int a = Integer.valueOf(num.substring(0, 2));
    int b = Integer.valueOf(num.substring(2));
    if (ori == a * b) {
        if ((a % 10 == 0) && (b % 10 == 0)) {
            return false;
        }
        return true;
    }
    return false;
}

工程代码:吸血鬼数字

发布了20 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/kiba_zwei/article/details/104088138