組合數計算-java


排列組合是計算應用經常使用的算法,通常使用遞歸的方式計算,但是由於n!的過於大,暴力計算很不明智。一般使用以下兩種方式計算。

一,遞歸的思想:假設m中取n個數計算排列組合數,表示為comb(m,n)。那么comb(m,n)= comb(m-1,n-1)+comb(m-1,n)

解釋思想,從m個球中取出n個球可以分成兩種情況相加,從m個球中取出一個球,如果它屬於n,還需要從m-1中取出n-1個球;如果它不屬於n,則需要從m-1中取出n個球

根據這種思想可以通過遞歸的思想計算組合數:

private static long comb(int m,int n){if(n==0)
            return 1;
        if (n==1) 
            return m;
        if(n>m/2)
            return comb(m,m-n);
        if(n>1)
            return comb(m-1,n-1)+comb(m-1,n);  
    
return -1; //通過編譯需要,數字無實際意義
}

適用遞歸計算,當數字較大時,遞歸深度過深,會相對耗時,甚至堆棧溢出。如果對性能有要求,可以建立鍵-值對,存儲計算結果,防止,反復計算。

static Map<String,Long> map= new HashMap<String, Long>();
private static long comb(int m,int n){
        String key= m+","+n;
        if(n==0)
            return 1;
        if (n==1) 
            return m;
        if(n>m/2)
            return comb(m,m-n);
        if(n>1){
            if(!map.containsKey(key))
                map.put(key, comb(m-1,n-1)+comb(m-1,n));
            return map.get(key);
        }
        return -1;
    }

二,對數的計算思想:跟據定義,comb(m,n)=m!/(m-n)!n!

兩邊取對數,log(comb(m,n))=log(m!/n!)-log((m-n)!)

計算之后,再通過exp計算最終結果。優點,不會出現數組越界,缺點:計算非常大的數字時,由於精度誤差,結果轉化為整數時可能有偏差

 private static double comb_log(int m,int n){
        int  i;
        if(n>m-n) n=m-n;
        double s1=0.0;
        double s2=0.0;
        for (int j = m-n+1; j <=m; j++) {
            s1+=Math.log(j);
        }
        for (int j = 1; j <=n; j++) {
         s2+=Math.log(j);
        }
        return Math.exp(s1-s2);
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM