• 组合数计算-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);
        }
    本博客所有内容为原创,转载需征求作者同意。
  • 相关阅读:
    【分治法】线性时间选择(转)
    【分治法】最接近点对问题(转)
    概率DP入门总结 16题(转)
    动态规划初探及什么是无后效性? (转)
    第15章DP(转)
    整数快速乘法/快速幂+矩阵快速幂+Strassen算法 (转)
    矩阵乘法的理解(转)
    算法导论第4章习题与思考题(转)
    Transaction Script模式
    注册服务
  • 原文地址:https://www.cnblogs.com/xueyudlut/p/9498275.html
Copyright © 2020-2023  润新知