吸血鬼数

简单了解吸血鬼数

今天看文档,突然看到一个奇怪的名字——“吸血鬼数”。
大概查了一下,这种数字有正常的吸血鬼数,伪吸血鬼数和质吸血鬼数。

正常的吸血鬼数,有以下特征:
1.位数为偶数;
2.由两个数字相乘得到,并且得到的乘积数字中,包含这两个数字拥有的全部数字,单个数字的数量也是一致的;
3.不以两个0结尾。

比如:21×60 = 1260,其中乘积1260就是正常的吸血鬼数,因为该数字包含了乘数21和被乘数60所拥有的所有数字。21和60即是该吸血鬼数的两个尖牙。

再比如:210×600 = 126000,因为210和600都以0为个位数(结尾),所以乘积126000就不是一个吸血鬼数。

再比如:31×33 = 1023,因为乘积1023中,拥有乘数31和被乘数33没有的数字“0”和“2”,所以乘积1023也不是一个吸血鬼数。

一个吸血鬼数可以多对尖牙。在四位数的吸血鬼数中,有一个数字125460,该数字就很特殊:204×615=246×510=125460。所以204、615和246、510都是125460的尖牙。

伪吸血鬼数:和正常的吸血鬼数唯一不同的就是,其位数可以是奇数。

质吸血鬼数:尖牙是质因数(能整除给定正整数的质数)的吸血鬼数,例如117067, 124483, 146137, 371893, 536539。

查找吸血鬼数

因为有点空余时间,所以打算用java实现一下正常吸血鬼数的查找逻辑。

实现时,遵循的基本查找规则,就是正常吸血鬼数拥有的那3个特征。

查找的实现方式有多种,下面是我比较喜欢的一个实现方式。

该实现方式可以查找任意指定位数(位数必须是偶数)的吸血鬼数。

小伙伴们可以自己拷贝代码执行一下即可看到输出结果。

Java代码

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 查找吸血鬼数字
 * 数字特点:
 * 位数为偶数
 * 由两个数字相乘得到,并且得到的乘积数字中,包含这两个数字拥有的全部数字,单个数字的数量也是一致的
 * 不已以两个0结尾
 * @author Alisallon
 */
public class VampireTools {

    private static class VampireData {
        private int m; // 乘数
        private int n; // 被乘数
        private int v; // 乘积

        private VampireData(int m, int n, int v) {
            this.m = m;
            this.n = n;
            this.v = v;
        }
    }

    public static void main(String[] args) {
        // 查找4位数范围内的吸血鬼数字
        System.out.println("查找4位数范围内的吸血鬼数字");
        findVampireNum(4);

        // 查找6位数范围内的吸血鬼数字
        System.out.println("查找6位数范围内的吸血鬼数字");
        findVampireNum(6);

//        // 查找8位数范围内的吸血鬼数字
//        System.out.println("查找8位数范围内的吸血鬼数字");
//        findVampireNum(8);
    }

    /**
     * 查找指定位数的吸血鬼数字
     * @author Alisallon
     *
     * @param digits int 指定位数
     */
    private static void findVampireNum(int digits) {
        if (digits < 4) {
            System.out.println("查找的位数至少是4位");
            return;
        }
        if (digits % 2 != 0) {
            System.out.println("查找的位数必须数偶数");
            return;
        }
        // 计算开始查找的位置
        int startNum = Double.valueOf(Math.pow(10, digits / 2 - 1)).intValue();
        // 计算结束查找的位置
        int endNum = Double.valueOf(Math.pow(10, digits / 2)).intValue() - 1;
        // 查找开始时间
        long startTime = System.currentTimeMillis();
        // 存放满足条件的吸血鬼数字对象,注意防止出现重复组合,比如21 * 60 和 60 * 21
        Map<String, VampireData> vampireMap = new HashMap<>();
        for (int m = startNum; m < endNum; m++) {
            for (int n = startNum; n < endNum; n++) {
                // 排除长度不相等的两个数字
                if (String.valueOf(m).length() != String.valueOf(n).length()) {
                    continue;
                }
                int value = m * n;
                // 排除小于最小乘积和大于最大乘积的乘积
                if (value < startNum * endNum || value > startNum * endNum * 10 - 1) {
                    continue;
                }
                // 去除以两个0结尾的乘积
                if (value % 100 == 0) {
                    continue;
                }
                // 检测指定两个数字的乘积是否是吸血鬼数字
                checkNumIsVampireNum(m, n, vampireMap);
            }
        }
        // 查找结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("吸血鬼数字查找时间: " + (endTime - startTime) + "ms");
        Set<Map.Entry<String, VampireData>> entrySet = vampireMap.entrySet();
        // 存放吸血鬼数字对象,用于排序显示
        List<VampireData> valueList = new ArrayList<>();
        // 保存非重复的吸血鬼数字
        Set<Integer> valueSet = new HashSet<>();
        for (Map.Entry<String, VampireData> entry : entrySet) {
            valueList.add(entry.getValue());
            valueSet.add(entry.getValue().v);
        }
        System.out.println("吸血鬼数字数量: " + vampireMap.size() + " 其中重复的数量:" + (vampireMap.size() - valueSet.size()));
        // 对valueList降序排序
        valueList.sort(Comparator.comparingInt(o -> o.v));
        for (VampireData vampireData : valueList) {
            // 控制台输出结果
            System.out.println(vampireData.m + " * " + vampireData.n + " = " + vampireData.v);
        }
    }

    /**
     * 检测指定两个数字的乘积是否是吸血鬼数字
     * @author Alisallon
     *
     * @param m          int
     * @param n          int
     * @param vampireMap Map<String, VampireData> 存放满足条件的吸血鬼数字对象,注意防止出现重复组合,比如21 * 60 和 60 * 21
     */
    private static void checkNumIsVampireNum(int m, int n, Map<String, VampireData> vampireMap) {
        char[] charArray = concat(String.valueOf(m).toCharArray(), String.valueOf(n).toCharArray());
        char[] valueStrArray = String.valueOf(m * n).toCharArray();
        for (char aCharArray : charArray) {
            // 乘积必须包含两个乘数拥有的所有数字
            // 检测乘积字符数组中指定的字符,并替换为其他非数组字符
            if (!checkAndReplaceChar(aCharArray, valueStrArray)) {
                return;
            }
        }
        // 判断乘积字符数组中,是否还有数字,如果还有数字,则表示m * n的值,不是吸血鬼数字
        String valueStr = String.valueOf(valueStrArray);
        Pattern p = Pattern.compile(".*\\d+.*");
        Matcher matcher = p.matcher(valueStr);
        if (!matcher.matches()) {
            // 乘积字符数组中没有数字了,全部被替换为其他非数组字符,m * n的值是吸血鬼数字
            // 比较大小,是为了防止出现重复组合,比如21 * 60 和 60 * 21, 在这里统一成 21 * 60
            if (m < n) {
                vampireMap.put(m + " * " + n, new VampireData(m, n, m * n));
            } else {
                vampireMap.put(n + " * " + m, new VampireData(n, m, m * n));
            }
        }
    }

    /**
     * 检测并替换乘积字符数组中指定的字符
     * @author Alisallon
     *
     * @param c              char 指定的字符
     * @param valueCharArray char[] 乘积字符数组
     * @return boolean 检测并替换结果
     */
    private static boolean checkAndReplaceChar(char c, char[] valueCharArray) {
        for (int index = 0; index < valueCharArray.length; index++) {
            if (valueCharArray[index] == c) {
                // 替换该位置字符为x,也可以是其他非数字字符
                valueCharArray[index] = 'x';
                return true;
            }
        }
        return false;
    }

    /**
     * 合并两个char数组
     * @author Alisallon
     *
     * @param first  char[]
     * @param second char[]
     * @return char[] 合并后的char数组
     */
    private static char[] concat(char[] first, char[] second) {
        char[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }
}

命令行输出(注意125460这个数字)

查找4位数范围内的吸血鬼数字
吸血鬼数字查找时间: 6ms
吸血鬼数字数量: 7 其中重复的数量:0
21 * 60 = 1260
15 * 93 = 1395
35 * 41 = 1435
30 * 51 = 1530
21 * 87 = 1827
27 * 81 = 2187
80 * 86 = 6880
查找6位数范围内的吸血鬼数字
吸血鬼数字查找时间: 148ms
吸血鬼数字数量: 142 其中重复的数量:1
201 * 510 = 102510
260 * 401 = 104260
210 * 501 = 105210
204 * 516 = 105264
150 * 705 = 105750
135 * 801 = 108135
158 * 701 = 110758
152 * 761 = 115672
161 * 725 = 116725
167 * 701 = 117067
141 * 840 = 118440
231 * 534 = 123354
281 * 443 = 124483
152 * 824 = 125248
231 * 543 = 125433
246 * 510 = 125460
204 * 615 = 125460
201 * 627 = 126027
261 * 486 = 126846
140 * 926 = 129640
179 * 725 = 129775
311 * 422 = 131242
323 * 410 = 132430
315 * 423 = 133245
317 * 425 = 134725
231 * 588 = 135828
351 * 387 = 135837
215 * 635 = 136525
146 * 938 = 136948
350 * 401 = 140350
351 * 414 = 145314
317 * 461 = 146137
156 * 942 = 146952
251 * 608 = 152608
261 * 585 = 152685
356 * 431 = 153436
240 * 651 = 156240
269 * 581 = 156289
165 * 951 = 156915
176 * 926 = 162976
396 * 414 = 163944
221 * 782 = 172822
231 * 750 = 173250
371 * 470 = 174370
231 * 759 = 175329
225 * 801 = 180225
201 * 897 = 180297
225 * 810 = 182250
281 * 650 = 182650
216 * 864 = 186624
210 * 906 = 190260
210 * 915 = 192150
327 * 591 = 193257
395 * 491 = 193945
275 * 719 = 197725
252 * 801 = 201852
255 * 807 = 205785
216 * 981 = 211896
341 * 626 = 213466
251 * 860 = 215860
323 * 671 = 216733
321 * 678 = 217638
248 * 881 = 218488
269 * 842 = 226498
276 * 822 = 226872
248 * 926 = 229648
338 * 692 = 233896
461 * 524 = 241564
422 * 581 = 245182
296 * 851 = 251896
350 * 725 = 253750
470 * 542 = 254740
323 * 806 = 260338
284 * 926 = 262984
437 * 602 = 263074
489 * 582 = 284598
420 * 678 = 284760
468 * 612 = 286416
320 * 926 = 296320
431 * 707 = 304717
431 * 725 = 312475
321 * 975 = 312975
534 * 591 = 315594
351 * 909 = 319059
336 * 951 = 319536
524 * 623 = 326452
342 * 963 = 329346
356 * 926 = 329656
530 * 635 = 336550
360 * 936 = 336960
392 * 863 = 338296
533 * 641 = 341653
366 * 948 = 346968
369 * 981 = 361989
392 * 926 = 362992
533 * 686 = 365638
585 * 630 = 368550
381 * 969 = 369189
383 * 971 = 371893
431 * 878 = 378418
435 * 870 = 378450
432 * 891 = 384912
465 * 831 = 386415
593 * 662 = 392566
446 * 908 = 404968
491 * 845 = 414895
641 * 650 = 416650
468 * 891 = 416988
482 * 890 = 428980
464 * 926 = 429664
476 * 941 = 447916
540 * 846 = 456840
546 * 840 = 458640
570 * 834 = 475380
624 * 780 = 486720
549 * 891 = 489159
545 * 899 = 489955
590 * 845 = 498550
681 * 759 = 516879
572 * 926 = 529672
563 * 953 = 536539
630 * 855 = 538650
588 * 951 = 559188
657 * 864 = 567648
650 * 875 = 568750
680 * 926 = 629680
650 * 983 = 638950
720 * 936 = 673920
788 * 926 = 729688
765 * 963 = 736695
843 * 876 = 738468
776 * 992 = 769792
875 * 902 = 789250
825 * 957 = 789525
855 * 927 = 792585
807 * 984 = 794088
891 * 909 = 809919
894 * 906 = 809964
858 * 951 = 815958
896 * 926 = 829696
891 * 945 = 841995
953 * 986 = 939658
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 一、计算机的发展史 01改变世界:没有计算器的日子怎么过——手动时期的计算工具 所谓计算机,顾名思义,就是用于计...
    文思汇集阅读 2,678评论 1 8
  • 机械时期(17世纪初~19世纪末) 手动时期的计算工具通常没有多少复杂的制作原理,许多经典的计算工具之所以强大,譬...
    逸之阅读 52,552评论 65 274
  • 第一章 站在阴森森的大铁门外,白芨不禁抖擞着,卷起袖子,是一层鸡皮疙瘩。 这里,就是父亲大人说的借住的地方吗? 穿...
    唐山耶阅读 5,095评论 0 12
  • 严梦佳 广州原上服饰 【日精进打卡第046天】。 ...
    严梦佳阅读 175评论 0 0
  • 我已经老了。真的觉得太漫长。八千多个日日夜夜里,群星璀璨,蚁虫蟋窣。天边的烟霞来了又去,葱茏的草木落了又起。人仓仓...
    拉斯阅读 388评论 0 0