得出四位数中的吸血鬼数字

前言:在看Java编程思想(第四版)第四章的时候,最后一个练习10是求四位数的吸血鬼数字,题目如下:
这里写图片描述

然后自己照着题目用循环写了一个答案:

/**
     * 练习10 :得出四位数中的吸血鬼数字
     * (吸血鬼数字是指位数为偶数的数字,可以由一对数字相乘而得到,而这对数字各包含乘积的一半位数的数字,其中从最初的数字中选取的数字可以任意排序,并且以两个0结尾的数字是不允许的)
     * @return void
     * @exception
     */
    public static void tenthExercise() {
        int count = 0;
        //循环所有四位数被除数
        for (int i = 1000; i < 10000; i++) {
            String iString = ((Integer)i).toString();
            //如果是以00结尾的数字则跳过
            if(iString.endsWith("00")) {
                continue;
            }
            //循环所有两位数除数
            for (int j = 10; j < 100; j++) {
                int result = i/j;
                String iResult = ((Integer)result).toString();
                //如果被除数/除数没有余数 && 商也为两位数
                if(i % j == 0 && iResult.length() == 2) {
                    count++;
                    //判断除数和商是否能组成该四位数
                    String first = ((Integer)(j / 10)).toString(); 
                    String second = ((Integer)(j % 10)).toString(); 
                    String thrid = ((Integer)(result / 10)).toString(); 
                    String fourth = ((Integer)(result % 10)).toString(); 
                    String cc = iString;
                    if(cc.indexOf(first) != -1) {
                        cc = cc.replaceFirst(first, "");
                    }
                    if(cc.indexOf(second) != -1) {
                        cc = cc.replaceFirst(second, "");
                    }
                    if(cc.indexOf(thrid) != -1) {
                        cc = cc.replaceFirst(thrid, "");
                    }
                    if(cc.indexOf(fourth) != -1) {
                        cc = cc.replaceFirst(fourth, "");
                    }
                    if("".equals(cc.trim())) {
                        System.out.println("除数:" + j + ", 商:" +result);
                        System.out.println(i);
                        break;
                    }
                }
            }
        }
        System.out.println("count:" + count);
    }

但是发现自己的写的代码效率太低,循环次数太多,然后网上查到一种效率最高的算法,如下:
引用自:http://blog.csdn.net/java2000_net/article/details/3851203

/**
 * 吸血鬼数字,高效率版本.<br>
 * 一个4位数字,可以拆分2个2位数数字的乘积,顺序不限。<br>
 * 比如 1395 =15 * 93
 * 
 * @author 老紫竹(laozizhu.com)
 */
public class Vampire {
  public static void main(String[] arg) {
    String[] ar_str1, ar_str2;
    int sum = 0;
    int from;
    int to;
    int i_val;
    int count = 0;
    // 双重循环穷举
    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;
        }
        count++;
        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 + "组吸血鬼数");
    System.out.println(count);
  }
}

此段代码刚开始有点看不懂,后面多看几次并配合博客里面的讲解才慢慢的看懂,首先是双重循环穷举:

 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++) {

因为求的是4位数的,所以在i从10开始增长的时候,要使i*j=四位数,则j至少要大于1000/i,并且小于10000/i,所以才有了这双重循环。至于当1000/i小于i+1的时候使用i+1是为了避免j取之前i已经循环过的数,比如20*50和50*20。

然后再是下面这段代码:

     // 下面的这个代码,我个人并不知道为什么,汗颜
     if (i_val % 100 == 0 || (i_val - i - j) % 9 != 0) {
       continue;
     }

可以看老紫竹博客下面的解释,很明确了

i_val % 100 == 0 是为了过滤尾数为00的四位数

关于算法的解释,来自网友MT502
假设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整除,所以可以直接过滤其他数字。

我准许做一下
x*y = val = 1000a + 100b + 10c + d;
我们假设
x = 10a + b, y = 10c + d
则
  x*y-x-y
= val - x-y
= (1000a + 100b + 10c + d) - (10a+b) - (10c +d) = 990a + 99b + 9c
= 9 * (110a + 11b + c);

对于别的组合可能性,结果一样,比如
x=10c+a; y=10d+b;
  x*y-x-y
= val - x-y
= (1000a + 100b + 10c + d) - (10c+a) - (10d +b) = 999a + 99b -9d
= 9 * (110a + 11b -d);

当然也能被9整除了

当然还有其他的方法,在此就不一一列举了,有兴趣可以深入研究研究。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值