java实现吸血鬼数字的三个想法(附官方答案)
2016-08-25 20:05
330 查看
自己写了一种方法,优化过后还可以,不过取巧。网上找了两种方法,从运行时间上来看比自己的方法慢
官方的一种方法,运行时间简直快到不可思议,真没法了。
1、第一个方法(我自己写的)
从四位数入手,大量if语句,都是复制粘贴的
2、第二个方法(网上的)
从2位数入手,但缺点是需要引入java.util.Arrays
3、第三个方法(网上的)
突然发现和第二个好像一样??但是要慢很多
4、第四个方法(官方的答案)
简直快到无解,找到了一个新的数学关系来优化!!
代码如下:
官方答案解析:
官方的答案从两位数入手
首先剔除了((num1 * num2) % 9 != (num1 + num2) % 9)
因为假设吸血鬼数字
num=a*1000+b*100+c*10+d=(a*10+b)*(c*10+d);
num1=(a*10+b);
num2=(c*10+d);
num-num1-num2=a*990+b*99=9*(a*110+b*11)
这个数可以被9整除,也就是说吸血鬼数字被9除的余数和两个基数的和被9除的余数相等。
所以不符合这个条件的都被剔除
然后这一段
巧妙地利用float到int的隐式转换得到了两基数的各个单个数字和两基数乘积的单个数字,放在两个数组里
然后
双层循环对比数组,如果全部相同(这里指两个集合相同,不管数组索引,所以需要16次比较),则符合条件。
分析下来,官方的答案主要是巧妙地利用隐式转换得到各个位数从而节省了大量时间
我的方法是把四位数变成字符串,在变成char数组,然后取到各个位数,这样调用Integer.toString()和toCharArray()就浪费了大量时间
如果把我的
改成
这样消耗的时间也是0毫秒,但是还是需要在循环次数上取巧。就是第一次运算,知道范围之后限定循环范围来减少循环次数
改进代码
官方的一种方法,运行时间简直快到不可思议,真没法了。
1、第一个方法(我自己写的)
从四位数入手,大量if语句,都是复制粘贴的
2、第二个方法(网上的)
从2位数入手,但缺点是需要引入java.util.Arrays
3、第三个方法(网上的)
突然发现和第二个好像一样??但是要慢很多
4、第四个方法(官方的答案)
简直快到无解,找到了一个新的数学关系来优化!!
代码如下:
package com.thinkinjava.vampire; import java.util.Arrays; public class VampireNumber { private static void showfournum1() { String string=""; int a1,a2,a3,a4; int x1=0,x2=0; char[] ch=new char[5]; for (int i=1260;i<=6880;i++) { if (i % 100 ==0)continue; string=Integer.toString(i); ch=string.toCharArray(); a1=((int)(ch[0])-48); a2=((int)(ch[1])-48); a3=((int)(ch[2])-48); a4=((int)(ch[3])-48); if (a1!=0&&a3!=0) { x1=a1*10+a2; x2=a3*10+a4; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} x1=a1*10+a4; x2=a3*10+a2; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} } if (a1!=0&&a2!=0) { x1=a1*10+a3; x2=a2*10+a4; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} x1=a1*10+a4; x2=a2*10+a3; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} } if (a1!=0&&a4!=0) { x1=a1*10+a2; x2=a4*10+a3; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} x1=a1*10+a3; x2=a4*10+a2; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} } if (a2!=0&&a3!=0) { x1=a2*10+a4; x2=a3*10+a1; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} x1=a2*10+a1; x2=a3*10+a4; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} } if (a2!=0&&a4!=0) { x1=a2*10+a3; x2=a4*10+a1; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} x1=a2*10+a1; x2=a4*10+a3; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} } if (a3!=0&&a4!=0) { x1=a3*10+a2; x2=a4*10+a1; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} x1=a3*10+a1; x2=a4*10+a2; if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;} } } } private static void showfournum2() { String[] ar_str1, ar_str2; int sum = 0; int from; int to; int i_val; // 双重循环穷举 for (int i = 10; i < 100; i++) { // j=i+1避免重复 from = Math.max(1000 / i, i + 1); to = Math.min(10000 / i, 100); for (int j = from; j < to; j++) { i_val = i * j; if (i_val % 100 == 0 || (i_val - i - j) % 9 != 0) { 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("共找到" + sum + "组吸血鬼数"); } private static void showfournum3() { // for (int i = 11; i < 100; i++) { for (int j = i; j < 100; j++) { int k = i * j; String kStr = Integer.toString(k); String checkStr = Integer.toString(i) + Integer.toString(j); if (kStr.length() != 4) continue; char[] kChar = kStr.toCharArray(); char[] checkChar = checkStr.toCharArray(); Arrays.sort(kChar); Arrays.sort(checkChar); boolean isVampire = Arrays.equals(kChar, checkChar); if (isVampire) { System.out.println(i + " * " + j + " = " + k); } } } } private static void showfournum4() { // 官方参考答案 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(num1 + " * " + num2 + " : " + product); } } } /* * Output: 15 * 93 : 1395 21 * 60 : 1260 21 * 87 : 1827 27 * 81 : * 2187 30 * 51 : 1530 35 * 41 : 1435 80 * 86 : 6880 *///:~ } public static void main(String[] args) { long start=System.currentTimeMillis(); // VampireNumber.showfournum1(); // VampireNumber.showfournum2(); // VampireNumber.showfournum3(); VampireNumber.showfournum4(); long time=System.currentTimeMillis()-start; System.out.println("耗时"+time+"毫秒"); } }
官方答案解析:
官方的答案从两位数入手
首先剔除了((num1 * num2) % 9 != (num1 + num2) % 9)
因为假设吸血鬼数字
num=a*1000+b*100+c*10+d=(a*10+b)*(c*10+d);
num1=(a*10+b);
num2=(c*10+d);
num-num1-num2=a*990+b*99=9*(a*110+b*11)
这个数可以被9整除,也就是说吸血鬼数字被9除的余数和两个基数的和被9除的余数相等。
所以不符合这个条件的都被剔除
然后这一段
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;
巧妙地利用float到int的隐式转换得到了两基数的各个单个数字和两基数乘积的单个数字,放在两个数组里
然后
for (int x = 0; x < 4; x++) for (int y = 0; y < 4; y++) { c111 if (productDigit[x] == startDigit[y]) { count++; productDigit[x] = -1; startDigit[y] = -2; if (count == 4) System.out.println(num1 + " * " + num2 + " : " + product); } }
双层循环对比数组,如果全部相同(这里指两个集合相同,不管数组索引,所以需要16次比较),则符合条件。
分析下来,官方的答案主要是巧妙地利用隐式转换得到各个位数从而节省了大量时间
我的方法是把四位数变成字符串,在变成char数组,然后取到各个位数,这样调用Integer.toString()和toCharArray()就浪费了大量时间
如果把我的
string=Integer.toString(i); ch=string.toCharArray(); a1=((int)(ch[0])-48); a2=((int)(ch[1])-48); a3=((int)(ch[2])-48); a4=((int)(ch[3])-48);
改成
a1=i /1000; a2=i %1000 /100; a3=i %1000 %100/10; a4=i%1000%100%10;
这样消耗的时间也是0毫秒,但是还是需要在循环次数上取巧。就是第一次运算,知道范围之后限定循环范围来减少循环次数
改进代码
private static void showfournum1()
{
String string="";
int a1,a2,a3,a4;
int x1=0,x2=0;
char[] ch=new char[5];
for (int i=1260;i<=6880;i++)
{
if (i % 100 ==0)continue;
/*string=Integer.toString(i); ch=string.toCharArray(); a1=((int)(ch[0])-48); a2=((int)(ch[1])-48); a3=((int)(ch[2])-48); a4=((int)(ch[3])-48);*/
a1=i /1000;
a2=i %1000 /100;
a3=i %1000 %100/10;
a4=i%1000%100%10;
if (a1!=0&&a3!=0)
{
x1=a1*10+a2;
x2=a3*10+a4;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
x1=a1*10+a4;
x2=a3*10+a2;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
}
if (a1!=0&&a2!=0)
{
x1=a1*10+a3;
x2=a2*10+a4;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
x1=a1*10+a4;
x2=a2*10+a3;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
}
if (a1!=0&&a4!=0)
{
x1=a1*10+a2;
x2=a4*10+a3;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
x1=a1*10+a3;
x2=a4*10+a2;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
}
if (a2!=0&&a3!=0)
{
x1=a2*10+a4;
x2=a3*10+a1;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
x1=a2*10+a1;
x2=a3*10+a4;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
}
if (a2!=0&&a4!=0)
{
x1=a2*10+a3;
x2=a4*10+a1;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
x1=a2*10+a1;
x2=a4*10+a3;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
}
if (a3!=0&&a4!=0)
{
x1=a3*10+a2;
x2=a4*10+a1;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
x1=a3*10+a1;
x2=a4*10+a2;
if (x1*x2==i){System.out.println(i+" = "+x1+"*"+x2);continue;}
}
}
}
相关文章推荐
- Java实现对三个数字的排序----简单易懂
- 吸血鬼数字检验之java实现
- 吸血鬼数字的实现(thinking in java练习题)
- 4位吸血鬼数字的java实现
- JAVA实现的吸血鬼数字算法,高效率版本(已有网友给出算法说明)
- [Java实现]吸血鬼数字问题的坑和尝试
- THINKING IN JAVA中吸血鬼数字题目的答案,稍作修改
- JAVA实现的吸血鬼数字算法,高效率版本(已有网友给出算法说明)
- 用友面试题答案 - java归并算法实现
- .Net/C#/VB/T-SQL/Java 实现: 将天文数字转换成中文大写 (2000 年前的思路,打劫的,一点儿技术含量都没有)
- 转 .Net/C#/VB/T-SQL/Java/Script 实现: 将天文数字转换成中文大写 (2000 年前的思路,打劫的,一点儿技术含量都没有)
- Java2下Applet数字签名具体实现方法
- Jsp/Java代码分离.实现页面真正的代码分离 测试代码是否按想法运行,下载原代码
- 三个利用Java实现zip压缩/解压缩方法
- Java2下Applet数字签名具体实现方法
- 基础:Java里数字转字符串前面自动补0的实现
- Java2下Applet数字签名具体实现方法
- .Net/C#/VB/T-SQL/Java 实现: 将天文数字转换成中文大写 (2000 年前的思路,打劫的,一点儿技术含量都没有)
- 数字金额转换中文大写Java实现
- Java2下Applet数字签名具体实现方法