zoukankan      html  css  js  c++  java
  • 2020-09-12:手撕代码:最小公倍数,复杂度多少?

    福哥答案2020-09-12:#福大大架构师每日一题#
    最大公约数
    1.【更相减损法】=【等值算法】,避免了取模运算,但是算法性能不稳定,最坏时间复杂度为O(max(a, b)))。
    2.【辗转相除法】,迭代和递归,时间复杂度不太好计算,可以近似为O(log(max(a, b))),但是取模运算性能较差。
    3.【Stein算法】,不但避免了取模运算,而且算法性能稳定,时间复杂度为O(log(max(a, b)))。
    4.【试除法】,时间复杂度是O(min(a, b)))。

    两个数的最小公倍数
    1.【利用最大公约数】。时间复杂度是O(最大公约数)。
    2.【试乘法】。时间复杂度是O(min(a, b)))。

    n个数的最小公倍数
    1.【遍历法】,时间复杂度是O[n*O(最大公约数)]。
    2.【二分法】,分桶法中的一种。并行和非并行。时间复杂度是O[n*O(最大公约数)]。

    代码用go语言编写,代码如下:

    package test39_lcm
    
    import (
        "fmt"
        "testing"
    )
    
    //go test -v -test.run TestLcm
    func TestLcm(t *testing.T) {
        fmt.Println("----最大公约数")
        fmt.Println(Gcd1(36, 42), "    1.更相减损法")
        fmt.Println(Gcd2(36, 42), "    2.辗转相除法")
        fmt.Println(Gcd3(36, 42), "    3.Stein算法")
        fmt.Println(Gcd4(36, 42), "    4.试除法")
        fmt.Println("----两个数的最小公倍数")
        fmt.Println(Lcm1(36, 42), "    1.利用最大公约数")
        fmt.Println(Lcm2(36, 42), "    2.试乘法")
        fmt.Println("----N个数的最小公倍数")
        fmt.Println(LcmN1([]int{2, 4, 6, 8}), "    1.遍历法")
        fmt.Println(LcmN2([]int{2, 4, 6, 8}), "    2.二分法")
    }
    
    //1.最大公约数:【更相减损法】=【等值算法】
    func Gcd1(a int, b int) int {
        k := 1
    
        //这段代码其实可以不用的,但是算法介绍里有除以2的操作,故有这段代码
        if true {
            for a&1 == 0 && b&1 == 0 {
                a /= 2
                b /= 2
                k <<= 1
            }
        }
    
        //两数相减
        for a != b {
            //保证第一个数大于等于第二个数
            if a < b {
                a, b = b, a
            }
            a, b = b, a-b
        }
        return b * k
    }
    
    //2.最大公约数:【辗转相除法】
    func Gcd2(a int, b int) int {
        if true {
            //迭代
            for b != 0 {
                a, b = b, a%b
            }
            return a
        } else {
            //递归
            if a%b == 0 {
                return b
            } else {
                return Gcd2(b, a%b)
            }
        }
    
    }
    
    //3.最大公约数:【Stein算法】
    func Gcd3(a int, b int) int {
        k := 1
    
        //最大公约数跟系数k有关,不能省略
        for a&1 == 0 && b&1 == 0 {
            a /= 2
            b /= 2
            k <<= 1
        }
    
        for a != b {
            //a和b,做除以2的操作
            for a&1 == 0 {
                a >>= 1
            }
            for b&1 == 0 {
                b >>= 1
            }
    
            //a和b经过除以2的操作后,可能相等了
            if a == b {
                break
            }
    
            //保证第一个数大于等于第二个数
            if a < b {
                a, b = b, a
            }
    
            //做减法操作
            a, b = b, a-b
        }
    
        return a * k
    }
    
    //4.最大公约数:【试除法】
    func Gcd4(a int, b int) int {
        //保证第一个数大于等于第二个数
        if a < b {
            a, b = b, a
        }
    
        //试除
        for i := b; i >= 2; i-- {
            if a%i == 0 && b%i == 0 {
                return i
            }
        }
    
        //试除失败,1就是最大公约数
        return 1
    }
    
    //1.两个数的最小公倍数:【利用最大公约数】
    func Lcm1(a int, b int) int {
        return a / Gcd2(a, b) * b
    }
    
    //2.两个数的最小公倍数:【试乘法】
    func Lcm2(a int, b int) int {
        //保证第一个数大于等于第二个数
        if a < b {
            a, b = b, a
        }
    
        //试乘
        for i := 1; i < b; i++ {
            if i*a%b == 0 {
                return i * a
            }
        }
    
        //试乘失败,两个数的乘积就是最小公倍数
        return a * b
    }
    
    //1.n个数的最小公倍数:【遍历法】
    func LcmN1(s []int) int {
        ret := 1
        for i := len(s) - 1; i >= 0; i-- {
            ret = Lcm1(ret, s[i])
        }
        return ret
    }
    
    //2.n个数的最小公倍数:【二分法】
    func LcmN2(s []int) int {
        slen := len(s)
        if slen == 1 {
            return s[0]
        } else {
            if true {
                //并行
                ch := make(chan int, 0)
                go func() {
                    ch <- LcmN2(s[0 : slen/2])
                }()
                go func() {
                    ch <- LcmN2(s[slen/2:])
                }()
                return Lcm1(<-ch, <-ch)
            } else {
                //非并行
                return Lcm1(LcmN2(s[0:slen/2]), LcmN2(s[slen/2:]))
            }
        }
    }
    

      敲 go test -v -test.run TestLcm 命令,结果如下:

  • 相关阅读:
    传参总结
    装mongondb数据库
    es6的几种写法
    在github上搭建自己的主页
    云主机,虚拟主机,VPS
    TDD vs. BDD
    流量统计分析软件比较
    深入浅出Node js 读书笔记 思维导图
    浏览器的工作原理解析
    开源搜索引擎的比较
  • 原文地址:https://www.cnblogs.com/waitmoon/p/13658697.html
Copyright © 2011-2022 走看看