掘金更文挑战
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
专栏 —— 算法Trick
番外更新一些面试或刷题时可能会用到的小算法,小技巧,脑筋急转弯。是一些你知道就能更快更优雅,不知道就会很伤脑筋的小知识。
一、四平方和定理
对整数的平方分解是一道颇有难度的算法题,一般考察点是动态规划。即使使用动态规划,因为每确定一个数,都要在比它小的平方数中搜索,组合出该数,复杂度依然很高。但其实,已经证明任何一个正整数,至多被表示为四个正整数的平方和。并且,当且仅当n != 4^k * (8*m + 7)时,n可以被表示为至多三个正整数的平方和。因此,当 n = 4^k * (8*m + 7)时,只能被表示为四个正整数的平方和。
所以对于要将一个数表示为完全平方数的和的问题,可以分为下面四种情况进行计算:
- 该数为完全平方数
- 该数为完全平方和
- 该数满足
n = 4^k * (8*m + 7) - 不满足上面三种情况,只能被分成三个完全平方数的和
二、快速幂与快速乘法与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的数,是不是和快速幂很像。