package test4;

import java.util.Arrays;

/**
* 从TIJ中第4章的练习10看到“吸血鬼数字”,以下几种方法实现以及执行时间对比
* 找出四位数的所有吸血鬼数字
* 吸血鬼数字是指位数为偶数的数字,可以由一对数字相乘而得到,而这对数字各包含乘积的一半位数的数字,
* 其中从最初的数字中选取的数字可以任意排序.
* 以两个0结尾的数字是不允许的。
* 例如下列数字都是吸血鬼数字
* 1260=21*60
* 1827=21*87
* 2187=27*81
*/
public class Test1 { public static void main(String[] args) {
long start = System.nanoTime();
fun1();
long end = System.nanoTime();
System.out.println("方法1所用时间:" + (end - start)+"\n"); start = System.nanoTime();
fun2();
end = System.nanoTime();
System.out.println("方法2所用时间:" + (end - start)+"\n"); start = System.nanoTime();
fun3();
end = System.nanoTime();
System.out.println("方法3所用时间:" + (end - start)+"\n"); start = System.nanoTime();
fun4();
end = System.nanoTime();
System.out.println("方法4所用时间:" + (end - start)+"\n");
} private static void fun1() {
//参考答案
int sum = 0;
int[] startDigit = new int[4];
int[] productDigit = new int[4];
for (int num1 = 10; num1 <= 99; num1++)
for (int num2 = num1; num2 <= 99; num2++) {
// Pete Hartley's theoretical result:
// If x·y is a vampire number then
// x·y == x+y (mod 9)
if ((num1 * num2) % 9 != (num1 + num2) % 9)
continue;
int product = num1 * num2;
startDigit[0] = num1 / 10;
startDigit[1] = num1 % 10;
startDigit[2] = num2 / 10;
startDigit[3] = num2 % 10;
productDigit[0] = product / 1000;
productDigit[1] = (product % 1000) / 100;
productDigit[2] = product % 1000 % 100 / 10;
productDigit[3] = product % 1000 % 100 % 10;
int count = 0;
for (int x = 0; x < 4; x++)
for (int y = 0; y < 4; y++) {
if (productDigit[x] == startDigit[y]) {
count++;
productDigit[x] = -1;
startDigit[y] = -2;
if (count == 4) {
System.out.println("第" + sum + "组: " + num1 + " * " + num2 + " : " + product);
sum++;
}
}
}
}
System.out.println("方法1共找到" + sum + "组吸血鬼数");
} private static void fun2() {
String[] ar_str1, ar_str2;
int sum = 0;
int from;
int to;
int i_val;
for (int i = 10; i < 100; i++) {
from = Math.max(1000 / i, i + 1);
to = Math.min(10000 / i, 100);
// 2个数的乘积是4位数(大于等于1000,小于10000),i确定时,另一个数范围随之确定
for (int j = from; j < to; j++) {
i_val = i * j;
if (i_val % 100 == 0 || (i_val - i - j) % 9 != 0) {
// (i_val - i - j) % 9 != 0 的理解:
// 假设val = 1000a + 100b + 10c + d, 因为满足val = x * y, 则有x =
// 10a + b, y = 10c + d
// 可得val - x - y = 990a + 99b + 9c = 9 * (110a + 11b + c),
// 所以val - x - y能被9整除。
// 满足该条件的数字必定能被9整除,可以直接过滤其他数字。
continue;
}
ar_str1 = String.valueOf(i_val).split("");
ar_str2 = (String.valueOf(i) + String.valueOf(j)).split("");
Arrays.sort(ar_str1);
Arrays.sort(ar_str2);
if (Arrays.equals(ar_str1, ar_str2)) {
sum++;
System.out.println("第" + sum + "组: " + i + "*" + j + "=" + i_val);
}
}
}
System.out.println("方法2共找到" + sum + "组吸血鬼数");
} private static void fun3() {
int sum = 0;
for (int i = 11; i < 100; i++) {
for (int j = i; j < 100; j++) {
int k = i * j;
// 有另一种变为字符串来操作,比较发现下面的这种方法耗时更少
int[] a = { k / 1000, k / 100 % 10, k / 10 % 100 % 10, k % 1000 % 100 % 10 };
int[] b = { i % 10, i / 10, j % 10, j / 10 };
Arrays.sort(a);
Arrays.sort(b);
if (Arrays.equals(a, b)) {
sum++;
System.out.println("第" + sum + "组: " + i + " * " + j + " = " + k);
}
}
}
System.out.println("方法3共找到" + sum + "组吸血鬼数");
} private static void fun4() {
//逆向思维
String[] targetNum = null;
String[] gunNum = null;
int sum = 0;
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位数则跳过
targetNum = String.valueOf(i_target).split("");
gunNum = (String.valueOf(i) + String.valueOf(j)).split("");
Arrays.sort(targetNum);
Arrays.sort(gunNum);
if (Arrays.equals(targetNum, gunNum)) {
sum++;
System.out.println("第" + sum + "组: " + i_target + "=" + i + "*" + j);
}
}
}
System.out.println("方法4找到" + sum + "个吸血鬼数字。");
}
}

执行结果:

第0组: 15 * 93 : 1395
第1组: 21 * 60 : 1260
第2组: 21 * 87 : 1827
第3组: 27 * 81 : 2187
第4组: 30 * 51 : 1530
第5组: 35 * 41 : 1435
第6组: 80 * 86 : 6880
方法1共找到7组吸血鬼数
方法1所用时间:4880538
第1组: 15*93=1395
第2组: 21*60=1260
第3组: 21*87=1827
第4组: 27*81=2187
第5组: 30*51=1530
第6组: 35*41=1435
第7组: 80*86=6880
方法2共找到7组吸血鬼数
方法2所用时间:43971275 第1组: 15 * 93 = 1395
第2组: 21 * 60 = 1260
第3组: 21 * 87 = 1827
第4组: 27 * 81 = 2187
第5组: 30 * 51 = 1530
第6组: 35 * 41 = 1435
第7组: 80 * 86 = 6880
方法3共找到7组吸血鬼数
方法3所用时间:19352070 第1组: 1395=15*93
第2组: 1260=21*60
第3组: 1827=21*87
第4组: 2187=27*81
第5组: 1530=30*51
第6组: 1435=35*41
第7组: 6880=80*86
方法4找到7个吸血鬼数字。
方法4所用时间:125098134

JAVA_吸血鬼数字 多种方法实现的更多相关文章

  1. Java 吸血鬼数字

    非常羞愧(事实上没什么羞愧.水平就这样).搞了半晌才写出来了一个Java 版求四位吸血鬼数字的方法 吸血鬼数字是指位数为偶数的数字.能够由一对数字相乘而得到.而这对数字各包括乘积的一半位数的数字,当中 ...

  2. str.format() 格式化数字的多种方法

    Python2.6 开始,新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能. 基本语法是通过 {} 和 : 来代替以前的 % . format 函数可以接受不限个参数 ...

  3. Java 找出四位数的全部吸血鬼数字 基础代码实例

    /**  * 找出四位数的全部吸血鬼数字  * 吸血鬼数字是指位数为偶数的数字,能够由一对数字相乘而得到,而这对数字各包括乘积的一半位数的数字,当中从最初的数字中选取的数字能够随意排序.  * 以两个 ...

  4. Java 找出四位数的所有吸血鬼数字 基础代码实例

    /**  * 找出四位数的所有吸血鬼数字  * 吸血鬼数字是指位数为偶数的数字,可以由一对数字相乘而得到,而这对数字各包含乘积的一半位数的数字,其中从最初的数字中选取的数字可以任意排序.  * 以两个 ...

  5. 《Thinking in Java》习题——吸血鬼数字

    最近在看<Java编程思想>,这本书非常棒,不愧是Java程序员的圣经.看到第四章,后面有道题目很有意思,于是就自己做了做.

  6. 无线加密的多种方法及其区别(WEP WPA TKIP EAP)

    无线加密的多种方法及其区别(WEP WPA TKIP EAP) 无线网络的安全性由认证和加密来保证. 认证允许只有被许可的用户才能连接到无线网络: 加密的目的是提供数据的保密性和完整性(数据在传输过程 ...

  7. javascript实现保留两位小数的多种方法

    第一种方法:javascript实现保留两位小数一位自动补零代码实例:第一种方法介绍一下如何实现对数字保留两位小数效果,如果数字的原本小数位数不到两位,那么缺少的就自动补零,这个也是为了统一的效果,先 ...

  8. CSS导航菜单水平居中的多种方法

    CSS导航菜单水平居中的多种方法 在网页设计中,水平导航菜单使用是十分广泛的,在CSS样式中,我们一般会用Float元素或是「display:inline-block」来解决.而今天主要讲解如何让未知 ...

  9. 用 Python 排序数据的多种方法

    用 Python 排序数据的多种方法 目录 [Python HOWTOs系列]排序 Python 列表有内置就地排序的方法 list.sort(),此外还有一个内置的 sorted() 函数将一个可迭 ...

随机推荐

  1. springboot 使用itextpdf 框架实现多个图片合成一个pdf文件

    以下两个方法引入头 import com.lowagie.text.*; import com.lowagie.text.pdf.PdfWriter; import org.apache.pdfbox ...

  2. linux互传文件nc命令

    使用nc命令可以很快的在两台主机传递文件,且不需要在同一网段,只要设置好端口即可. 一.安装(CentOS下) yum install -y nc  (需要root权限,可以用加上sudo) 二.使用 ...

  3. SpringMvc redirect

    SpringMVC redirect 核心 首先网上百度到的资源基本已经够用, 留作记录. SpringMVC-redirect重定向跳转传值 虽然这哥们也是转的, 但又没有留源地址. 因此 ... ...

  4. SPI 用户空间的读写操作

    spi_device 虽然用户空间不需要直接用到spi_device结构体,但是这个结构体和用户空间的程序有密切的关系,理解它的成员有助于理解SPI设备节点的IOCTL命令,所以首先来介绍它.在内核中 ...

  5. shell-009:删除字母

    把一个文件里的前100行中有字母的行删除:再把101-200行的字母去掉 #!bin/bashsed '101.200s/[a-zA-Z]//g' filesed -n '1.100'p file | ...

  6. AI简单平移追踪算法

    1.比较坐标追踪法 追踪者会不停地比较自身和目标的x坐标和y坐标,每x和y上一个单位的移动为一个周期,该算法虽然简单好用,但实用性差且不智能化,如果追踪者数量增加,路线会显得单调,由于都是先走个对角线 ...

  7. Stopwatch类学习

    1.概述:给一条大MSDN的链接关于Stopwatch类最详细的教程 ,然后看着教程自己手动敲一边,加深映象,好记性不如烂键盘,哈哈,开个玩笑! 2.类位置:这个类在哪里,这个是重点,虽然C#IDE很 ...

  8. Chrome DevTools的15个使用技巧(译)

    谷歌浏览器如今是Web开发者们所使用的最流行的网页浏览器.伴随每六个星期一次的发布周期和不断扩大的强大的开发功能,Chrome变成了一个必须掌握的工具.大多数前端开发者可能熟悉关于chorme的许多特 ...

  9. 对于SQL Server 2008删除或压缩数据库日志的方法

    由于数据库日志增长被设置为“无限制”,所以时间一长日志文件必然会很大,一个400M的数据库居然有4G的LOG文件,严重占用了磁盘空间.由于主要是做OLAP,所以数据库本身不会有大变动,所以日志也就没有 ...

  10. 深入理解java集合框架之---------Linked集合 -----构造函数

    linked构造函数 1.LinkedList(): 构造一个空列表的集合 /** * 序列化 */ private static final long serialVersionUID = 1090 ...