在一般的程序设计书里面,都有关于求两个数的最大公因数的算法(或者叫做最大公约数)。求两个数的最大公约数算法用的最多的是辗转相除法。

基本思路就是

getCommonMutiple(a,b){  //这里假定a 是较大的数,实际编码时要先判断谁大谁小;

r = a%b;

if(r != 0){

a = b;

b = r;

getCommonMutiple(a ,b);

}

return b;

}

但是如何求N个数的最大公因数呢?(N > 1)

在初等数学里,有这么几个定理

1、任何一个整数,都可以分解为素数因子的乘积

比如

24 = 2* 2* 2 * 3;

26 = 2 * 13;

分解时应该从2开始分解起

2、若干个数的最大公因数是共同素数因子的乘积

比如 求 48 60 72 的最大公因数

48 = 2*2*2*2*3

60 = 2*2*3*5

72 = 2*2*2*3*3

共同的素数因子为 2 * 2 * 3 = 12 所以他们的最大公因数就是12

有了这两个知识点之后,我们开始写程序

详见代码

/***Aug 25, 2013*Copyright(c)JackWang*All rights reserve*@Author <a href="mailto:wangchengjack@163.com">JackWang</a>
*/
package com.example.blog;import java.util.ArrayList;
import java.util.List;/*** 计算机里求最大公因数的方法通常是辗转相除法* 但是这个方法的缺陷在与一次只能求两个数的最大公因数* 如果需要求若干个数的最大公因数呢?* 需求:设计一个算法,可以求出若干个整数的最大公因数* @author Administrator**/
public class CommonMutiple {public static void main(String[] args) {int[] data1 = {26,13};int[] data2 = {735000,421160,238948};int[] data3 = {1008,1260,882,1134};int result1 = getCommonMutiple(data1);int result2 = getCommonMutiple(data2);int result3 = getCommonMutiple(data3);System.out.println(result1);System.out.println(result2);System.out.println(result3);}/*** 得到最大公倍数的方法* @param data1  传入数组* @return  返回最大公倍数*/private static int getCommonMutiple(int[] data1) {List<List<Integer>> divisorList = new ArrayList<>();for(int data :data1){divisorList.add(getDivisors(data));}return getResult(divisorList);}/*** 得到一个数的全部素数因子* @param data 传入一个整数* @return  返回素数因子*/private static List<Integer> getDivisors(int data) {List<Integer> primeList = new ArrayList<>();int k = Math.abs(data);int sum = 1;if(!isPrime(data)){ //如果这个数是素数的话,直接返回int len = (int)Math.sqrt(Math.abs(data));for(int i = 2; i <= len; i++){ //任何一个数都可以分解为素数因子的乘积if(isPrime(i)){while(data % i == 0){sum *= i;if(sum <= k){primeList.add(i);}data = data / i;if(isPrime(data)){primeList.add(data);sum *= data;break;}}if(sum == k)break;}}}else {primeList.add(data);}return primeList;}private static boolean isPrime(int data) {for(int i = 2;i <= Math.sqrt(Math.abs(data)); i++){if (data % i == 0)return false;}return true;}/*** 通过将各个数的素数因子传入该方法,得到最大公因数* 实际就是求一组数的交集* 如果这组数存在最大公因数,则最大公因数必定在素数因子最小的集合里* @param divisorList* @return*/private static int getResult(List<List<Integer>> divisorList) {int result = 1;   //存储最终结果,如果返回是1的话,则说明不存在最大公因数for(int element :divisorList.get(0)){boolean flag = true; for(int j = 1;j < divisorList.size();j++){if(!divisorList.get(j).contains(element)){flag = false;break;}divisorList.get(j).remove(divisorList.get(j).indexOf(element));}if (flag) {result *= element;}}//       int k = divisorList.get(0).size();
//      int j = 0;   //记录最小元素数的脚标
//      for(int i = 1 ; i < divisorList.size(); i++){
//          if (divisorList.get(i).size() <= k) {
//              k = divisorList.get(i).size();
//              j = i;
//          }
//      }
//
//      for(List<Integer> list :divisorList){
//          divisorList.get(j).retainAll(list);
//      }
//
//      for (int i = 0; i <divisorList.get(j).size() ; i++) {
//          System.out.println(divisorList.get(j).get(i));
//
//      }
//
//      if(divisorList.get(j).size() != 0){
//          for (int r : divisorList.get(j)) {
//              result = result * r;
//          }
//      }return result;}
}

这里两个较为重要的算法是

1、如何将一个整数分解为素数因子的乘积

2、如何找出若干个素数因子中共同的素数因子

对于第一个算法,对应的代码为

 private static List<Integer> getDivisors(int data) {List<Integer> primeList = new ArrayList<>();int k = Math.abs(data);int sum = 1;if(!isPrime(data)){ //如果这个数是素数的话,直接返回int len = (int)Math.sqrt(Math.abs(data));for(int i = 2; i <= len; i++){ //任何一个数都可以分解为素数因子的乘积if(isPrime(i)){while(data % i == 0){sum *= i;if(sum <= k){primeList.add(i);}data = data / i;if(isPrime(data)){primeList.add(data);sum *= data;break;}}if(sum == k)break;}}}else {primeList.add(data);}return primeList;}

思路为:先判断传入的数据是否为素数,如果是素数直接加到list中返回即可,否则

从素数2开始分解,如果能整除2,则说明2是一个素因子,继续整除2,如果不能整除了先要判断这个已经是不是一个素数了,如果是的话就要加到list里,这是非常容易忽略的地方,我也是用26这个数据做测试的时候才发现(26 = 2* 13)在判断过程中,要将素数因子乘积存到sum变量里,因为当sum = data时就应该已经分解完成了。

对于第二个算法,代码如下

 private static int getResult(List<List<Integer>> divisorList) {int result = 1;   //存储最终结果,如果返回是1的话,则说明不存在最大公因数for(int element :divisorList.get(0)){boolean flag = true; for(int j = 1;j < divisorList.size();j++){if(!divisorList.get(j).contains(element)){flag = false;break;}divisorList.get(j).remove(divisorList.get(j).indexOf(element));}if (flag) {result *= element;}}return result;}

将素数因子集合作为参数传进来,以第一个list中的元素作为基(最大公因数的素数因子必定存在于任何一个整数的素数因子集合中,一开始我想的是先找出最小size集合再去判断,其实没必要这么做,平均时间复杂度比这个要高(特殊极端情况除外)),依次取出来,如果存在于剩下的每一个list中,说明这个元素是公共的,则将结果保存于result中,一旦哪个list中不存在,则说明不是公共的,这里的flag标记是判断是否存在于每个list中的一个开关,只有遍历完剩下的list,才能加到result的结果中。需要注意的是每一次从一个list中找出一个公共的素数因子,需要将这个元素从list中删除,并且是删除最先出现的。这里有个地方需要注意的是我们一开始就是从最小的素数因子存入的,所以每个list中的因子都是从小到大排好序的。

关键知识点就是这些,这个程序虽然简单,但是却花了我将近3个小时的思考才写出来,可见我的数学和算法知识还有进步的地方,需要多加努力,多写代码!

求N个数的最大公因数(算法)相关推荐

  1. c语言在多个数数最大数,求多个数的最大公因数算法 C语言

    我们用(a1,a2,....)表示最大公因数  [a1,a2,.....]表示最小公倍数 1.两个数的最大公因数 辗转相除法,可以直接使用C语言自带的 c = __gcd(a,b): 辗转相除法原理可 ...

  2. 求两个数的最大公因数

    这里提供两种方法:一种比较朴素,基本思想很简单就是按照从大到小的找能够匹配的因数,找到就返回:另一种是欧几里得算法,该算法的核心思想是,当前两个数的最大公因数的也是这两个数模的与其中一个元素的的最大公 ...

  3. Python两种方式求多个数的最大公因数(HCF)和最小公倍数(LCM)

    Python两种方式求多个数的最大公因数(HCF)和最小公倍数(LCM) 最大公因数 1. 列表排序 2. 将列表分为两部分 3. 求最大公因数的质因子 4. 得到结果 5. 完整程序 最小公倍数 另 ...

  4. LeetCode刷题: 【914】卡牌分组(求N个数的最大公因数)

    1. 题目 2. 思路 如何求N个数的最大公因数呢?(N > 1) 在初等数学里,有这么几个定理 1.任何一个整数,都可以分解为素数因子的乘积 比如 24 = 2* 2* 2 * 3: 26 = ...

  5. 求3个数的最小公倍数算法之数论进阶

    求3个数的最小公倍数算法之数论进化 https://blog.csdn.net/number1killer/article/details/104960548 求3个数的最小公倍数算法之数论再细化 h ...

  6. 求3个数的最小公倍数算法之数论再细化

    求3个数的最小公倍数之便捷算法(C# ) https://blog.csdn.net/number1killer/article/details/104681168 求3个数的最大公约数之算法研究集成 ...

  7. Java求三个数的最小公倍数算法改进(化境)

    之前在<Java求3个数的最小公倍数LCM,要求LCM小于11亿时计算结果正确(在CPU性能小于1.8GHz的情况下)>一文中"避免了之前的算法最大计算量的情况"(相对 ...

  8. 求3个数的最小公倍数算法之数论进化

    求3个数的最小公倍数算法之数论再细化 https://blog.csdn.net/number1killer/article/details/104902304 求3个数的最小公倍数之便捷算法(C# ...

  9. 求n个数的最大公因数和最小公倍数(c)

    设计要点 可以通过反复求两个正整数的最大公因数和最小公倍数的方法来实现. 规定(a,b)为a,b的最大公因数,{a,b}为最小公倍数. 对于3个或3个以上的正整数,最大公约数与最小公倍数有以下性质: ...

最新文章

  1. Wix学习整理(7)——在开始菜单中为HelloWorld添加卸载快捷方式
  2. 【密码学02】密码系统原理及数学背景
  3. C# 多线程 线程池(ThreadPool) 2 如何控制线程池?
  4. Ajax Control Toolkit 32个服务器端控件
  5. 关于Delphi中的字符串的详细分析
  6. 华为手机微信网络连接到服务器失败怎么办,微信H5支付在华为手机里报错 网络环境未能通过安全验证,请稍后再试 怎么解决啊 试了好多方法也不行...
  7. Hadoop之HDFS常用Shell命令
  8. MySql+Socket 完成数据库的增查Demo
  9. Groovy在Spring中的简单使用实例
  10. macos安装盘第三方工具制作_简单制作OSXYosemite10.10正式版U盘USB启动安装盘方法教程(全新安装Mac系统)下载|异次元软件世界...
  11. linux下alias命令详解
  12. android 自定义布局 根据布局获取类,阿里高级Android面试题解析:Android自定义View—布局过程的自定义...
  13. 处女座的砝码-数学推论
  14. python 中 函数的使用!!!
  15. rabbitmq高可用集群搭建踩坑
  16. 问题 E: 分分分 学生的命根
  17. Canvas 绘制圆形图片、绘制圆角矩形图片
  18. unable to access https://github.com/....解决方法
  19. 00后学习创作娱乐生活宅家必备:钉钉、书旗小说、橙瓜码字
  20. 壹号本 深度 linux,壹号本4代迷你笔记本开箱,10.1英寸大小,平板电脑二合一设计...

热门文章

  1. 支付宝接口 java_JAVA调用支付宝的直充接口
  2. 11 个非常实用的 Python 和 Shell 拿来就用脚本实例!
  3. 网页中调用matlab,在C#的Web项目中调用Matlab代码的步骤
  4. 在按键精灵里使用奥迦插件查找和枚举窗口句柄
  5. 转:MSN君最后的十个瞬间
  6. Java输入一个数,判断该数是否为质数
  7. 网易互娱数据成本优化治理实践
  8. 【Maven】自定义插件(新建项目开始):AbstractMojo,Mojo,pluginGroups,build,plugin,execution,phase,goals
  9. 广东工业大学 Anyviewce C语言 习题九
  10. 基于B/S的大学毕业生就业信息管理系统