zoukankan      html  css  js  c++  java
  • 奇妙的算法【2】- 韩信点兵问题优化

     1,问题介绍

      ①淮安民间传说着一则故事——“韩信点兵”,其次有成语“韩信点兵,多多益善”。

    韩信带1500名兵士打仗,战死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信很快说出人数:104。

      ②在一千多年前的《孙子算经》中,有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”按照今天的话来说:一个数除以3余2,除以5余3,除以7余2,求这个数。这样的问题,也有人称为“韩信点兵”。它形成了一类问题,也就是初等数论中的解同余式。

      ③问题:一个数除以3余2,除以5余3,除以7余2,求符合条件的最小数。

    2,结题思路

    思路1:【暴力求解法-遍历,效率低】

    直接从0一直计算到很大的数值来进行判断

        public static int dealSingle1(int index0,int index1,int index2){//暴力求解
            boolean a,b,c;
            for(int i=0;i<Integer.MAX_VALUE;i++){
                a=(i%3==index0);
                b=(i%5==index1);
                c=(i%7==index2);
                if(a&&b&&c){
                    return i;
                }
            }
            return -1;
        }

    思路2:【利用数学的知识进行运算,进一步优化,应该是速度最快的】

      先列出除以3余2的数:2,5,8,11,14,17,20,23,26……

      再列出除以5余3的数:3,8,13,18,23,28……
      这两列数中,首先出现的公共数是8。3与5的最小公倍数是15。两个条件合并成一个就是8+15×整数,列出这一串数是8,23,38,……,再列出除以7余2的数2,9,16,23,30……就得出符合题目条件的最小数是23。
      事实上,我们已把题目中三个条件合并成一个:被105除余23。
        public static int dealSingle2(int index0,int index1,int index2) {//2,数学方法求解
            long startTime =  System.currentTimeMillis();
            int num=0,num1=0;
            for(int i=0;i<Integer.MAX_VALUE;i++){
                num=5*i+index1;//修改优化,直接使用较大大数进行取值,进一步加快速度
                if(num%3==index0){
                    break;
                }
            }
            for(int i=0;i<Integer.MAX_VALUE/15;i++){
                num1=num+15*i;
                if(num1%7==index2){
                    long endTime =  System.currentTimeMillis();
                    System.out.println("方法2:数学优化,耗时:"+(endTime-startTime));
                    return num1;
                }
            }
            return -1;
        }

    思路3:【由大数主导数值运算,速度也很快】

        public static int dealSingle3(int index0,int index1,int index2){//处理单个数据
            long startTime =  System.currentTimeMillis();
            int num=-1;
            boolean a,b;
            for(int i=0;i<Integer.MAX_VALUE/7;i++){
                num=i*7+index2;
                a=(num%3==index0);
                b=(num%5==index1);
                if(a&&b){
                    long endTime =  System.currentTimeMillis();
                    System.out.println("方法3:数学优化,耗时:"+(endTime-startTime));
                    return num;
                }
            }
            return num;
        }

     3,问题引申

      计算出韩信点兵的所有结果【3,5,7全部为素数,那么在0~(3*5*7-1)这个范围内的所有数据都是其中的一种情况】

        public static int[][][] dealAll(){//每次只计算一次,直到所有数据
            int[][][] arr=new int[3][5][7];
            for(int i=0;i<(3*5*7);i++){
                arr[i%3][i%5][i%7]=i;
            }
            return arr;
        }
  • 相关阅读:
    JS中的constructor与prototype
    HTTP状态码
    CSS HACK 及常见问题
    js常见怪异
    js深拷贝和浅拷贝
    浏览器渲染
    google全球地址大全
    从function前面的!想到的
    2048
    js判定IE
  • 原文地址:https://www.cnblogs.com/Mufasa/p/11409388.html
Copyright © 2011-2022 走看看