快速幂和大数求余解法

50. Pow(x, n)

思路

不用递归

设 res=1,则初始状态 x^n = x^n × res 。
在循环二分时,每当 n 为奇数时,将多出的一项 x 乘入 res ,则最终可化至 x^n = x^0 × res = res ,返回 res。

代码

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }

    public double quickMul(double x, long N) {
        if (N == 0) {
            return 1.0;
        }
        double y = quickMul(x, N / 2);
        return N % 2 == 0 ? y * y : y * y * x;
    }
}

不用递归

class Solution {
    public double myPow(double x, int n) {
        if(x == 0.0f) return 0.0d;
        long b = n;
        double res = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) res *= x;
            x *= x;
            b >>= 1;
        }
        return res;
    }
}

剑指 Offer 14- II. 剪绳子 II

思路

数学推导:
推论一: 将绳子以相等的长度等分为多段 ,得到的乘积最大。
推论二: 尽可能将绳子以长度 3 等分为多段时,乘积最大。

切分规则:

  1. 最优: 3 ;
    把绳子尽可能切为多个长度为 3 的片段,留下的最后一段绳子的长度可能为 0,1,2 三种情况。
  2. 次优: 2 ;
    若最后一段绳子长度为 2 ;则保留 。
  3. 最差: 1 。
    若最后一段绳子长度为 1 ;则应把一份 3+1 替换为 2+2,因为 2×2 > 3×1。

大数求余解法

大数求余问题: 在仅使用 int32 类型存储的前提下,正确计算 x^a 对 p 求余(即 x^a ⊙ p )的值。
解决方案: 循环求余 、 快速幂求余 ,其中后者的时间复杂度更低,两种方法均基于以下求余运算规则推出:

(xy) ⊙ p=[(x ⊙ p)(y ⊙ p)] ⊙ p

快速幂求余

# 求 (x^a) % p —— 快速幂求余
def remainder(x, a, p):
    rem = 1
    while a > 0:
        if a % 2: rem = (rem * x) % p
        x = x ** 2 % p
        a //= 2
    return rem

代码

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        int b = n % 3, p = 1000000007;
        long rem = 1, x = 3;
        for(int a = n / 3 - 1; a > 0; a /= 2) {
            if(a % 2 == 1) rem = (rem * x) % p;
            x = (x * x) % p;
        }
        if(b == 0) return (int)(rem * 3 % p);
        if(b == 1) return (int)(rem * 4 % p);
        return (int)(rem * 6 % p);
    }
}
posted @ 2021-10-12 23:30  当康  阅读(134)  评论(0编辑  收藏  举报