• 如何思索算法(一)


    如何思索算法(一)
    今天在刷网页的时候发现一个求最小公倍数的问题,感觉颇有意思就拿来看,有意思的不是题目而是我在解决该问题时所做的探索。
    题目:求能被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)*............

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

  • 相关阅读:
    Ubuntu下使用Sysvinit实现自定义服务(简单研究)
    Linux初始化init系统-Sysvinit、Upstart、Systemd
    Ubuntu查看系统版本的方法
    Linux查看文件内容命令:more(转)
    Linux查看文件内容命令:less(转)
    Ubuntu 16.04下MySQL 5.7.18取消开机启动(解决无法使用Sysvinit(update-rc.d/sysv-rc-conf)脚本关闭)
    为什么说Ubuntu的运行级别为2
    Ubuntu 16.04开机进入命令行(tty1)+分辨率调节+字体颜色设置+中文乱码解决(解决虚拟终端Ctrl+Alt+F1分辨率太大)
    Linux运行级别研究(转)
    Linux服务管理(Ubuntu服务管理工具sysv-rc-conf)(转)
  • 原文地址:https://www.cnblogs.com/danger/p/2939392.html
Copyright © 2020-2023  润新知