JavaScript求一组数的最小公倍数和最大公约数常用算法详解【面向对象,回归迭代和循环】


Posted in Javascript onMay 07, 2018

本文实例讲述了JavaScript求一组数的最小公倍数和最大公约数常用算法。分享给大家供大家参考,具体如下:

方法来自求多个数最小公倍数的一种变换算法(详见附录说明)

最小公倍数的算法由最大公约数转化而来。最大公约数可通过如下步骤求得:

(1) 找到a1,a2,..,an中的最小非零项aj,若有多个最小非零项则任取一个
(2) aj以外的所有其他非0项ak用ak mod aj代替;若没有除aj以外的其他非0项,则转到(4)
(3) 转到(1)
(4) a1,a2,..,an的最大公约数为aj

写了两个版本的javascript求公倍数和公约数,主要偏重于算法,没有太注意命名,很多就直接写的单字母名称。

0. 简单易懂的循环

function getMin(arr){
  var min = Infinity
  arr.forEach(function(item){
    if( item < min && item !=0 ){
      min = item
    }
  })
  return min
}
function howMuchZero(arr){
  var zerocount = 0
  arr.forEach( function(item){
    item === 0 ?
    zerocount++ : zerocount
  }
    )
  if(zerocount === arr.length -1) {
    return true
  }
  else return false
}
function maxDivi(arr){
  do {
  var min = getMin(arr)
  arr = arr.map((item)=> item===min? item:item%min
    )
  }
  while (!howMuchZero(arr))
  return getMin(arr)
}
function minMulti(arr){
  var totalMulti = arr.reduce((pre,item)=>
    pre = pre * item
    )
  var brr = arr.map((item)=>
    totalMulti/item
    )
  var brr_maxDivi = maxDivi(brr)
  return totalMulti/brr_maxDivi
}

1. function套function

var arr_minMulti, arr_maxdivi
function minMulti(arr){
  var totalmulti =
    arr.reduce((multi,curvalue) => multi * curvalue)
  if (totalmulti === 0) {
    arr_minMulti = 0
    return
  }
  var marr = arr.map((item) => totalmulti/item)
  maxDivisor(marr)
   arr_minMulti = totalmulti / arr_maxdivi
}
function maxDivisor(arr){
  var min = getMin(arr)
  if(min === Infinity) {
    arr_maxdivi = min
    return
  }
  var exparr = arr.filter(function(item){
      return (item !== min && item !== 0)
  })
  if(exparr.length === 0){
    arr_maxdivi = min
    return;
  }
  else{
    var modearr = arr.map(function(item){
      return (item === min||item===0)? item:item%min
    })
    console.log(modearr,'modearr')
    maxDivisor(modearr)
  }
}
function getMin(arr){
  var min = Infinity
  arr.forEach(function(item){
    if (item && item < min) {
      min = item
    }
  })
  return min
}
arr =[13,20,10,26]
minMulti(arr)
console.log('最小公倍数',arr_minMulti)

2. object oriented 面向对象

function maxDivisor(arr,origin){
  this.arr = arr
  this.min = this._getMin(arr)
  this.maxDivisor = this._getMaxDiv()
  if(origin){
    this.minMulti = this._getMinMulti()
  }
}
maxDivisor.prototype._getMin = function(arr) {
  var min = Infinity
  arr.forEach(item => min = (item && item < min)? item : min)
  return min
}
maxDivisor.prototype._getMaxDiv = function() {
  var arr_maxdivi
  var self = this,
    arr = this.arr
  function maxDivisor(arr){
    //console.log(self._getMin)
    var min = self._getMin.call(null,arr)
     console.log(min,'min')
    if(min === Infinity) {
      arr_maxdivi = 0
      return ;
    }
    var exparr = arr.filter( item => (item !== min && item != 0) )
    if(exparr.length === 0){
      arr_maxdivi = min
      return;
    }
    else{
      var modearr = arr.map(item =>
        (item === min || item === 0)? item : item % min
      )
      maxDivisor(modearr)
      }
  }
  maxDivisor(this.arr)
  return arr_maxdivi
}
maxDivisor.prototype._getMinMulti = function(){
  var arr = this.arr,
    arr_minMulti
  var totalmulti =
    arr.reduce((multi,curvalue) => multi * curvalue)
  if (totalmulti === 0) {
    return 0
  }
  else {
    var marr = arr.map((item) => totalmulti/item),
    b = new maxDivisor(marr,false)
    arr_minMulti = totalmulti / b.maxDivisor
    return arr_minMulti
  }
}
var a = new maxDivisor([12,9,6],true)
console.log(a)

附录:求多个数最小公倍数的一种变换算法原理分析

令[a1,a2,..,an] 表示a1,a2,..,an的最小公倍数,(a1,a2,..,an)表示a1,a2,..,an的最大公约数,其中a1,a2,..,an为非负整数。对于两个数a,b,有[a,b]=ab/(a,b),因此两个数最小公倍数可以用其最大公约数计算。但对于多个数,并没有[a1,a2,..,an]=M/(a1,a2,..,an)成立,M为a1,a2,..,an的乘积。例如:[2,3,4]并不等于24/(2,3,4)。即两个数的最大公约数和最小公倍数之间的关系不能简单扩展为n个数的情况。

这里对多个数最小公倍数和多个数最大公约数之间的关系进行了探讨。将两个数最大公约数和最小公倍数之间的关系扩展到n个数的情况。在此基础上,利用求n个数最大公约数的向量变换算法计算多个数的最小公倍数。

1.多个数最小公倍数和多个数最大公约数之间的关系

令p为a1,a2,..,an中一个或多个数的素因子,a1,a2,..,an关于p的次数分别为r1,r2,..,rn,在r1,r2,..,rn中最大值为rc1=rc2=..=rcm=rmax,最小值为rd1=rd2=..=rdt=rmin,即r1,r2,..,rn中有m个数所含p的次数为最大值,有t个数所含p的次数为最小值。例如:4,12,16中关于素因子2的次数分别为2,2,4,有1个数所含2的次数为最大值,有2个数所含2的次数为最小值;关于素因子3的次数分别为0,1,0,有1个数所含3的次数为最大值,有2个数所含3的次数为最小值。

对最大公约数有,只包含a1,a2,..,an中含有的素因子,且每个素因子次数为a1,a2,..,an中该素因子的最低次数,最低次数为0表示不包含[1]。

对最小公倍数有,只包含a1,a2,..,an中含有的素因子,且每个素因子次数为a1,a2,..,an中该素因子的最高次数[1]。

定理1:[a1,a2,..,an]=M/(M/a1,M/a2,..,M/an),其中M为a1,a2,..,an的乘积,a1,a2,..,an为正整数。

例如:对于4,6,8,10,有[4,6,8,10]=120,而M=4*6*8*10=1920,M/(M/a1,M/a2,..,M/an) =1920/(6*8*10,4*8*10,4*6*10,4*6*8)=1920/16=120。

证明:

M/a1,M/a2,..,M/an中p的次数都大于等于r1+r2+..+rn-rmax,且有p的次数等于r1+r2+..+rn-rmax的。这是因为

(1)M/ai中p的次数为r1+r2+..+rn-ri,因而M/a1,M/a2,..,M/an中p的次数最小为r1+r2+..+rn-rmax。

(2)对于a1,a2,..,an中p的次数最大的项aj(1项或多项),M/aj中p的次数为r1+r2+..+rn-rmax。

或者对于a1,a2,..,an中p的次数最大的项aj,M/aj中p的次数小于等于M/ak,其中ak为a1,a2,..,an中除aj外其他的n-1个项之一,而M/aj中p的次数为r1+r2+..+rn-rmax。

因此,(M/a1,M/a2,..,M/an)中p的次数为r1+r2+..+rn-rmax,从而M/(M/a1,M/a2,..,M/an)中p的次数为rmax。

上述的p并没有做任何限制。由于a1,a2,..,an中包含的所有素因子在M/(M/a1,M/a2,..,M/an)中都为a1,a2,..,an中的最高次数,故有[a1,a2,..,an]=M/(M/a1,M/a2,..,M/an)成立。

得证。

定理1对于2个数的情况为[a,b]=ab/(ab/a,ab/b)=ab/(b,a)=ab/(a,b),即[a,b]=ab/(a,b)。因此,定理1为2个数最小公倍数公式[a,b]=ab/(a,b)的扩展。利用定理1能够把求多个数的最小公倍数转化为求多个数的最大公约数。

2.多个数最大公约数的算法实现

根据定理1,求多个数最小公倍数可以转化为求多个数的最大公约数。求多个数的最大公约数(a1,a2,..,an)的传统方法是多次求两个数的最大公约数,即

(1)用辗转相除法[2]计算a1和a2的最大公约数(a1,a2)

(2)用辗转相除法计算(a1,a2)和a3的最大公约数,求得(a1,a2,a3)

(3)用辗转相除法计算(a1,a2,a3)和a4的最大公约数,求得(a1,a2,a3,a4)

(4)依此重复,直到求得(a1,a2,..,an)

上述方法需要n-1次辗转相除运算。

本文将两个数的辗转相除法扩展为n个数的辗转相除法,即用一次n个数的辗转相除法计算n个数的最大公约数,基本方法是采用反复用最小数模其它数的方法进行计算,依据是下面的定理2。

定理2:多个非负整数a1,a2,..,an,若aj>ai,i不等于j,则在a1,a2,..,an中用aj-ai替换aj,其最大公约数不变,即 (a1,a2,..,aj-1,aj,aj+1,..an)=(a1,a2,..,aj-1,aj-ai,aj+1,..an)。

例如:(34,24,56,68)=(34,24,56-34,68)=(34,24,22,68)。

证明:

根据最大公约数的交换律和结合率,有

(a1,a2,..,aj-1,aj,aj+1,..an)= ((ai,aj),(a1,a2,..,ai-1,ai+1,..aj-1,aj+1,..an))(i>j情况),或者

(a1,a2,..,aj-1,aj,aj+1,..an)= ((ai,aj),(a1,a2,..,aj-1,aj+1,..ai-1,ai+1,..an))(i<j情况)。

而对(a1,a2,..,aj-1,aj-ai,aj+1,..an),有

(a1,a2,..,aj-1,aj-ai,aj+1,..an)= ((ai, aj-ai),( a1,a2,..,ai-1,ai+1,.. aj-1,aj+1,..an))(i>j情况),或者

(a1,a2,..,aj-1,aj-ai,aj+1,..an)= ((ai, aj-ai),( a1,a2,..,aj-1,aj+1,.. ai-1,ai+1,..an))(i<j情况)。

因此只需证明(ai,aj)=( ai, aj-ai)即可。

由于(aj-ai)= aj-ai,因此ai,aj的任意公因子必然也是(aj-ai)的因子,即也是ai,( aj-ai)的公因子。由于aj = (aj-ai)+ai,因此ai,( aj-ai)的任意公因子必然也是aj的因子,即也是ai,aj的公因子。所以,ai,aj的最大公约数和ai,(aj-ai) 的最大公约数必须相等,即(ai,aj)=(ai,aj-ai)成立。

得证。

定理2类似于矩阵的初等变换,即

令一个向量的最大公约数为该向量各个分量的最大公约数。对于向量<a1,a2,..,an>进行变换:在一个分量中减去另一个分量,新向量和原向量的最大公约数相等。

求多个数的最大公约数采用反复用最小数模其它数的方法,即对其他数用最小数多次去减,直到剩下比最小数更小的余数。令n个正整数为a1,a2,..,an,求多个数最大共约数的算法描述为:

(1)找到a1,a2,..,an中的最小非零项aj,若有多个最小非零项则任取一个

(2)aj以外的所有其他非0项ak用ak mod aj代替;若没有除aj以外的其他非0项,则转到(4)

(3)转到(3)

(4)a1,a2,..,an的最大公约数为aj

例如:对于5个数34, 56, 78, 24, 85,有

(34, 56, 78, 24, 85)=(10,8,6,24,13)=(4,2,6,0,1)=(0,0,0,0,1)=1,

对于6个数12, 24, 30, 32, 36, 42,有

(12, 24, 30, 32, 36, 42)=(12,0,6,8,0,6)=(0,0,0,2,0,6)=(0,0,0,2,0,0)=2。

3. 多个数最小共倍数的算法实现

求多个数最小共倍数的算法为:

(1)计算m=a1*a2*..*an

(2)把a1,a2,..,an中的所有项ai用m/ai代换

(3)找到a1,a2,..,an中的最小非零项aj,若有多个最小非零项则任取一个

(4)aj以外的所有其他非0项ak用ak mod aj代替;若没有除aj以外的其他非0项,则转到(6)

(5)转到(3)

(6)最小公倍数为m/aj

上述算法在VC环境下用高级语言进行了编程实现,通过多组求5个随机数最小公倍数的实例,与标准方法进行了比较,验证了其正确性。标准计算方法为:求5个随机数最小公倍数通过求4次两个数的最小公倍数获得,而两个数的最小公倍数通过求两个数的最大公约数获得。

5. 结论

计算多个数的最小公倍数是常见的基本运算。n个数的最小公倍数可以表示成另外n个数的最大公约数,因而可以通过求多个数的最大公约数计算。求多个数最大公约数可采用向量转换算法一次性求得。

Javascript 相关文章推荐
[JS]点出统计器
Oct 11 Javascript
发现的以前不知道的函数
Sep 19 Javascript
动态控制Table的js代码
Mar 07 Javascript
javascript移动设备Web开发中对touch事件的封装实例
Jun 05 Javascript
一个获取第n个元素节点的js函数
Sep 02 Javascript
判断在css加载完毕后执行后续代码示例
Sep 03 Javascript
JavaScript比较两个对象是否相等的方法
Feb 06 Javascript
jQuery 限制输入字符串长度
Jun 20 Javascript
细说webpack源码之compile流程-rules参数处理技巧(2)
Dec 26 Javascript
使用layer弹窗和layui表单实现新增功能
Aug 09 Javascript
vue-router 前端路由之路由传值的方式详解
Apr 30 Javascript
Vue 的 v-model用法实例
Nov 23 Vue.js
详解VUE-地区选择器(V-Distpicker)组件使用心得
May 07 #Javascript
JavaScript实现的DOM树遍历方法详解【二叉DOM树、多叉DOM树】
May 07 #Javascript
Vue 实现树形视图数据功能
May 07 #Javascript
JavaScript 跨域之POST实现方法
May 07 #Javascript
ES6关于Promise的用法详解
May 07 #Javascript
React Form组件的实现封装杂谈
May 07 #Javascript
vue如何将v-for中的表格导出来
May 07 #Javascript
You might like
PHP 日期时间函数的高级应用技巧
2009/10/10 PHP
PHP第一季视频教程(李炎恢+php100 不断更新)
2011/05/29 PHP
合并ThinkPHP配置文件以消除代码冗余的实现方法
2014/07/22 PHP
php检查字符串中是否包含7位GSM字符的方法
2015/03/17 PHP
php把数组值转换成键的方法
2015/07/13 PHP
PHP中file_get_contents函数抓取https地址出错的解决方法(两种方法)
2015/09/22 PHP
laravel 5.3 单用户登录简单实现方法
2019/10/14 PHP
FusionCharts图表显示双Y轴双(多)曲线
2012/11/22 Javascript
jQuery链式操作如何实现以及为什么要用链式操作
2013/01/17 Javascript
jquery ajax的success回调函数中实现按钮置灰倒计时
2013/11/19 Javascript
node.js中的emitter.on方法使用说明
2014/12/10 Javascript
JavaScript中指定函数名称的相关方法
2015/06/04 Javascript
JS实现自动变化的导航菜单效果代码
2015/09/09 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
个人网站留言页面(前端jQuery编写、后台php读写MySQL)
2016/05/03 Javascript
jquery使用on绑定a标签无效 只能用live解决
2016/06/02 Javascript
微信小程序实现移动端滑动分页效果(ajax)
2017/06/13 Javascript
webpack配置打包后图片路径出错的解决
2018/04/26 Javascript
JS拖拽排序插件Sortable.js用法实例分析
2019/02/20 Javascript
python判断端口是否打开的实现代码
2013/02/10 Python
Python操作SQLite简明教程
2014/07/10 Python
Python实现的数据结构与算法之队列详解
2015/04/22 Python
安装Python的web.py框架并从hello world开始编程
2015/04/25 Python
详解Python的Django框架中的中间件
2015/07/24 Python
Python中取整的几种方法小结
2017/01/06 Python
python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE方法
2017/05/24 Python
利用python解决mysql视图导入导出依赖的问题
2017/12/17 Python
用python标准库difflib比较两份文件的异同详解
2018/11/16 Python
Python3数字求和的实例
2019/02/19 Python
Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
2019/10/17 Python
英语硕士生求职简历的自我评价
2013/10/15 职场文书
机械加工与数控专业自荐书
2014/06/04 职场文书
廉政教育的心得体会
2014/09/01 职场文书
2014公司年终工作总结
2014/12/19 职场文书
使用jpa之动态插入与修改(重写save)
2021/11/23 Java/Android
vue动态绑定style样式
2022/04/20 Vue.js