【番外】刷题、面试可能用到的小算法(2)

159 阅读2分钟

掘金更文挑战

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情


专栏 —— 算法Trick

番外更新一些面试或刷题时可能会用到的小算法,小技巧,脑筋急转弯。是一些你知道就能更快更优雅,不知道就会很伤脑筋的小知识。

一、四平方和定理

对整数的平方分解是一道颇有难度的算法题,一般考察点是动态规划。即使使用动态规划,因为每确定一个数,都要在比它小的平方数中搜索,组合出该数,复杂度依然很高。但其实,已经证明任何一个正整数,至多被表示为四个正整数的平方和。并且,当且仅当n != 4^k * (8*m + 7)时,n可以被表示为至多三个正整数的平方和。因此,当 n = 4^k * (8*m + 7)时,只能被表示为四个正整数的平方和。

所以对于要将一个数表示为完全平方数的和的问题,可以分为下面四种情况进行计算:

  1. 该数为完全平方数
  2. 该数为完全平方和
  3. 该数满足n = 4^k * (8*m + 7)
  4. 不满足上面三种情况,只能被分成三个完全平方数的和

二、快速幂与快速乘法与HashMap容量确认

面试很有可能问到的题目,快速幂题目会限制你使用pow函数,快速乘法会限制你使用乘法符号。此时如何以对数复杂度计算结果呢?

logn的复杂度计算pow(x, n)。将n转化为二进制数,每一位i上都计算出x^i的值,如果该位为1,则将其乘入到结果中。 代码如下:

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;
    }
}

快速乘法与上面的快速幂类似,不过是res从累乘变成了累加。

long mul(long a, long k) {
    long ans = 0;
    while (k > 0) {
        if ((k & 1) == 1) ans += a;
        k >>= 1;
        a += a;
    }
    return ans;
}

Java8 中,HashMap确定容量的算法也有这种思想:

为了HashMap散列的方便,一般HashMap的容量都是二次幂,但用户传入的时候可能并不遵守这一规则,下面的函数会找到第一个比传入值大的二次幂数。

static final int tableSizeFor(int cap) { 
    int n = cap - 1; //为了防止本来就是二次幂的容量翻倍
    n |= n >>> 1; 
    n |= n >>> 2; 
    n |= n >>> 4; 
    n |= n >>> 8; 
    n |= n >>> 16; 
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

在上面的移位操作中,第一次前2位被置为1,用上一步的结果作为计算工具。然后是4位,8位,成倍地将容量化为一个二进制全为1的数,是不是和快速幂很像。