如何思索算法(一)

如何思索算法(一)
今天在刷网页的时候发现一个求最小公倍数的问题,感觉颇有意思就拿来看,有意思的不是题目而是我在解决该问题时所做的探索。
题目:求能被1~n所有数整除的最小正数(最小公倍数)。
  一眼瞅去一点思路都没有,只想从1*2*3*4*.....*n的结果就一定能够除所有1到n。但是这个数不是最小的,因为存在因子冗余。比如说:能够被8整除的数一定可以被2整除,被9整除的数一定可以被3整除。下面来一步一步的思考如何解决该问题:
  考虑1~10的情况:1、2、3、4、5、6、7、8、9、10。设置一个因子数组factor(10)。
  首先,去除1,这一点毫无疑问,不解释。
  其次,选出素数2、3、5、7放入factor中。这些数一定是所求最小整数的因子,因为它们只能被1和自身整除。此时,factor[(10)={2、3、5、7}
  然后,剩下的数有4、6、8、9、10。分解因子:
  4=2*2;
  6=2*3;
  8=2*4;
  9=3*3;
  10=2*5;
  分析,去掉6和10,因为2*3=6,2*5=10,因为在我们的素数中存在2、3、5。如果要能被9整除则必须包含两个3,向factor中添加一个3。最后考虑4和8,如果要能被8整除则必须有2*4,因为求最小的整数,所以因子小的保留。到此,factor(10)={2、3、5、7、4、3}问题得到解决该最小整数是2*3*4*5*7*3=2520。
  考虑1~20的情况:1、2、3、4、5、6、7、8、9、10、11、12、13、14、15、16、17、18、19、20。设置一个因子数组factor。
  首先,从大到小缩减范围。能够被11、12、13、14、15、16、17、18、19、20整除的数一定可以整除11、12、13、14、15、16、17、18、19、20。
  其次,选出11~20中的素数加入factor中。此时factor(20)={11、13、17、19}。
  然后,剩下的数有12、14、15、16、18、20。分解因子:
  12=2*6---->2*2*3
  14=2*7
  15=3*5
  16=2*8----->2*2*4------->2*2*2*2
  20=2*10---->2*2*5
  对因子进行删重去除冗余,剩余2、2、5、7、4、3、3加入数组factor,此时factor(20)={2、2、5、7、4、3、3、11、13、17、19}
  结果为2*5*7*4*3*3*11*13*17*19=232792560。
  Factor(10)={2、3、5、7、4、3}
  factor(20)={2、5、7、4、3、3、11、13、17、19、2}
  发现规律了吗?
  现在我可以立即写出1~30的最小公倍数的因子
  Factor(30)={2,3,5,7,11,13,17,19,23,29,2,2,2,3,3,5}。
  红色的是1~30的所有素数。为什么在后边添加了2,2,2,3,3,5呢?因为在1~30中包含了16,25,27这三个特别数字,为什么特别,因为它们需要2的4次方,5的2次方和3的3次方得到。也就意味着在factor中必须出现4次,2次和3次。
  因此很容易得到该问题的算法实现了:
  1、计算1~n的所有素数{a1,a2,a3........an}
  2、依次从小到大检查素数的幂次方,记录下不大于n的幂次m。
  3、将该素数的m次方与其他素数累乘。
      4、重复2、3,直到所有素数都被检查完。

下面给出该问题的java实现

public static long 最小公倍数(int n){
        long result = 1;
        int primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
        List list = new ArrayList();
        List exlist = new ArrayList();
        for(int i=0;i<primes.length;i++){
            if(primes[i]<n){
                list.add(primes[i]);
            }
        }
        for(int i=0;i<list.size();i++){
            int t =(Integer) list.get(i);
            int q = 0;
            int multis=t;
            for(;;q++){
                multis*=t;
                if(multis>n){
                    for(int j=0;j<q;j++){
                        exlist.add(t);
                    }
                    break;
                }
            }
        }
        
        for(int i=0;i<list.size();i++){
            int t =(Integer) list.get(i);
            result*=t;
        }
        for(int i=0;i<exlist.size();i++){
            int t =(Integer) exlist.get(i);
            result*=t;
        }
        System.out.println(list.toString());
        System.out.println(exlist.toString());
        return result;
    }

 

 

其实,任何自然数都可以通过素数的n次幂的乘积表示,即

N=(2^n)*(3^n)*(5^n)*(7^n)*(11^n)*(13^n)*(17^n)*............

这也正是程序实现的数学支持。如果知道该公式,我们就可以省却很多功夫,不用一点一点自己去总结发现规律,一下就能知道如何解决,但是思维的延伸却不能这样懒省事,要积极的去进行探索才能迸出创造的火花。

 

posted on 2013-03-01 20:31  DangerSnake  阅读(363)  评论(2编辑  收藏  举报

导航

  您喜欢本文吗?即刻订阅"DangerSnake",精彩文章不再错过!现在就给我留个话吗?