奇妙的算法【2】- 韓信點兵問題優化

 1,問題介紹

  ①淮安民間傳說着一則故事——「韓信點兵」,其次有成語「韓信點兵,多多益善」。優化

韓信帶1500名兵士打仗,戰死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韓信很快說出人數:104。

  ②在一千多年前的《孫子算經》中,有這樣一道算術題:「今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二,問物幾何?」按照今天的話來講:一個數除以3餘2,除以5餘3,除以7餘2,求這個數。這樣的問題,也有人稱爲「韓信點兵」。它造成了一類問題,也就是初等數論中的解同餘式。spa

  ③問題:一個數除以3餘2,除以5餘3,除以7餘2,求符合條件的最小數。code

2,結題思路

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

直接從0一直計算到很大的數值來進行判斷blog

    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……get

  再列出除以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;
    }
相關文章
相關標籤/搜索