Description
吸血鬼数字是指位数为偶数的数字,可以由一对数字相乘得到,而这对数字的位数是原数字的一半位数,并且由组成原数字的各个位数组成,以两个0结尾的数字不是吸血鬼数字。
例如:1260 = 21 * 60 1827 = 21 * 87 2187= 27 * 81
求所有四位吸血鬼数字
解决方案一(逆向思维)
Analyse
通常思维是枚举所有的四位数来找出所有符合条件的吸血鬼数,然而,算法需要枚举的数实在是太多了,四位数的个数为9000个(我们暂且做粗略考虑,不做精细打算),算法的时间复杂度相对较高。逆向思维是,因为分解的乘数都是两位数,所以列举所有的两位数,求得结果要为四位数,再进一步判断是否满足吸血鬼数的条件(需要枚举的个数低于9000不要太多)。设置过滤条件
为了让算法更高效率的进行,就需要过滤一些可以迅速判断出不符合条件的枚举。
value=i*j (其中i < j,10 <= i <= 99)
判断j的循环范围,就至少需要两者的乘积可以构成四位数,所以1000/i和10000/i是一个界限。为了避免出现重复的乘积,还需和i+1比较大小。
假设value = 1000a + 100b + 10c + d, 因为满足val = i * j, 则有x = 10a + b, y = 10c + d
则value - i - j = 990a + 99b + 9c = 9 * (110a + 11b + c), 所以value - i - j能被9整除,其他的数位组合也是一样的,可以试一试(我是没想出来这个条件,只是在网上看到的,所以说啊,算法好就需要数学好!)。
所以满足该条件的数字必定能被9整除,所以可以直接过滤其他数字。- 源代码
import java.util.Arrays;
class Vampire{
/*
* 求出所有四位数的吸血鬼数
*/
public static void main(String[] args){
int value;
String[] sij;
String[] sv;
int count=0; //计数总共对比数据相等多少次,用以判断算法性能
int sum=0; //用以记录吸血鬼数的个数
//i:两个乘数中较小的一个,j:两个乘数中较大的一个
for(int i=10; i<100; i++){
int begin=Math.max(1000/i, i+1);
int end=Math.min(9999/i, 99);
for(int j=begin; j<=end; j++){
value=i*j;
if(value%100==0||(value-i-j)%9!=0)
continue;
count++; //进入到比较阶段
sij=(String.valueOf(i)+String.valueOf(j)).split("");
sv=String.valueOf(value).split("");
Arrays.sort(sij);
Arrays.sort(sv);
//将数组的内容进行比较
if(Arrays.equals(sij,sv)){
sum++;
System.out.println("第"+sum+"组: "+i+"*"+j+"="+value);
}
}
}
System.out.println("共找到"+sum+"组吸血鬼数");
System.out.println("对比字符串数组次数:"+count);
}
}
- 运行结果
第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
共找到7组吸血鬼数
对比字符串数组次数:232