Go 快速幂、模运算、组合数

快速幂

LeetCode 相关题目:50. Pow(x, n)

func myPow(x float64, n int) float64 {
    res := 1.0
    if n < 0 {
        x = 1 / x
        n = -n
    }
    for n > 0 {
        if n&1 == 1 {
            res *= x
        }
        x *= x
        n >>= 1
    }
    return res
}

int 类型的位数

当 n=−2^31 时,−n=2^31,这可比 32 位有符号整数的最大值(2^31-1)还大,难道不会溢出吗?

实际上,Golang 中 int 的位数取决于平台

  • 32 位系统:int 是 32 位
  • 64 位系统:int 是 64 位
package math

const (
    intSize = 32 << (^uint(0) >> 63) // 32 or 64
    // 32 位系统
    // ^uint(0):对无符号整数 0 按位取反,0xFFFFFFFF(32 个 1)
    // >> 63:右移 63 位,0xFFFFFFFF -> 0
    // 32 << 0:intSize = 32
    // 64 位系统
    // ^uint(0):对无符号整数 0 按位取反,0xFFFFFFFFFFFFFFFF(64 个 1)
    // >> 63:右移 63 位,0xFFFFFFFFFFFFFFFF -> 1
    // 32 << 1:intSize = 64
    
    MaxInt    = 1<<(intSize-1) - 1  // MaxInt32 or MaxInt64 depending on intSize.
    MinInt    = -1 << (intSize - 1) // MinInt32 or MinInt64 depending on intSize.
)

模运算

详见 分享丨模运算的世界:当加减乘除遇上取模(模运算恒等式/费马小定理/组合数)

// 加
(a + b) % MOD

// 把任意整数 a 取模到 [0,MOD-1] 中,无论 a 是正是负
(a % MOD + MOD) % MOD

// 减
(a - b + MOD) % MOD

// 乘
a * b % MOD

// 多个数相乘,要步步取模,防止溢出
a * b % MOD * c % MOD

// 除(MOD 是质数且 b 不是 MOD 的倍数)
a * modPow(b, MOD - 2, MOD) % MOD

取模快速幂

func modPow(x, n, mod int) int {
    res := 1
    for n > 0 {
       if n&1 == 1 {
          res = res * x % mod
       }
       x = x * x % mod
       n >>= 1
    }
    return res
}

组合数

直接通过阶乘计算会溢出,可以使用递推公式边乘边除:C(n,i)=C(n,i1)×ni+1i,i[1,m]C(n, i)=C(n, i-1)\times\frac{n-i+1}{i}, i\in[1, m]

C(n,0)=n!0!(n0)!=1C(n, 0)=\frac{n!}{0!(n-0)!}=1
C(n,1)=n!1!(n1)!=C(n,0)×n1+11C(n, 1)=\frac{n!}{1!(n-1)!}=C(n, 0)\times\frac{n-1+1}{1}
C(n,2)=n!2!(n2)!=C(n,1)×n2+12C(n, 2)=\frac{n!}{2!(n-2)!}=C(n, 1)\times\frac{n-2+1}{2}

C(n,m1)=n!(m1)!(nm+1)!=C(n,m2)×nm+2m1C(n, m-1)=\frac{n!}{(m-1)!(n-m+1)!}=C(n, m-2)\times\frac{n-m+2}{m-1}
C(n,m)=n!m!(nm)!=C(n,m1)×nm+1mC(n, m)=\frac{n!}{m!(n-m)!}=C(n, m-1)\times\frac{n-m+1}{m}
func comb(m, n int) int {
    // 利用对称性,减少计算量
    if m > n-m {
       m = n - m
    }
    res := 1
    for i := 1; i <= m; i++ {
       res = res * (n - i + 1) / i
    }
    return res
}

取模组合数

LeetCode 相关题目:3881. 恰好看到 K 个人的方向选择

func modComb(m, n, mod int) int {
    if m > n-m {
       m = n - m
    }
    numerator, denominator := 1, 1
    for i := 1; i <= m; i++ {
       numerator = numerator * (n - i + 1) % mod
       denominator = denominator * i % mod
    }
    return numerator * modPow(denominator, mod-2) % mod
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇