在算法刷题过程中,总会遇到一些小的公式计算,如质数,最大公约数,最小公倍数这些,特此总结一下。
1. 质数
一个正整数只能被1和它自身整除且大于1,那么这个数就是素数(质数)。
计算方法:使用开方去过滤,提高运行效率。
下面给出质数的判断,以及n以内的质数和个数。
import java.util.*;
public class Prime { // 质数计算和判断
public static void main(String[] args) {
int x = 97;
boolean Prime = isPrime(x);
System.out.println(Prime);
int n = 100;
calPrime(n);
}
// 判断质数,用开放根的方法
public static boolean isPrime(int x) {
int m = (int)(Math.sqrt(x) + 1);
for (int i = 2; i < m; i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
// 计算 n 以内的质数,以及质数个数
public static void calPrime(int n) {
int num = 0;
boolean flag = false;
List<Integer> res = new ArrayList<>();
for (int i = 2; i <= n; i++) {
if (i % 2 == 0 && i != 2) continue;
flag = true;
for (int j = 2; j <= Math.sqrt(i); j++) {
if (i % j == 0) {
flag = false;
break;
}
}
if (flag) {
res.add(i);
num++;
}
}
System.out.println(num);
for (int i = 0; i < res.size(); i++) {
System.out.print(res.get(i) + " ");
}
}
}
2. 牛顿迭代法
【牛顿迭代公式】
设r
是f(x) = 0
的根,选取x0
作为r
初始近似值,过点 (x0, f(x0))
作曲线y=f(x)
的切线L
,
切线L的方程为:y = f(x0) + f’(x0)(x-x0)
,
求出L
与x
轴交点的横坐标 x1 = x0 - f(x0) / f’(x0)
,称x1
为r
的一次近似值
过点(x1, f(x1))
作曲线y=f(x)
的切线,以此迭代,其中x(n+1)=x(n)-f(x(n))/f'(x(n))
,称为r
的n+1
次迭代值。
leetcode:69. x 的平方根
可转化为求x^2 - a = f(x)
的根
public int mySqrt(int x) {
if(x <= 1) {
return x;
}
int r = x / 2;
while(r > x / r) {
r = (r + x / r) / 2;
}
return r;
}
public double sqrt(double c) {
if(c < 0) return Double.NaN; //not a number
double err = le-15;
double t = c;
while(Math.abs(t - c/t) > err * t) {
t = (t + c / t) / 2.0;
}
return t;
}
求m的开n次方根
public static double mySqrtN(double m, double n) {
if (m == 0) return 0;
double err = 1e-8;
double t = m / 2, pre = m;
while (Math.abs(pre - t) > t * err) {
pre = t;
t = ((n - 1) * t + m / Math.pow(t, n - 1)) / n;
}
return t;
}
3. 最大公约数
线性检测法
public int gcd(int x, int y) {
int res = 1;
int min = Math.min(x, y);
for(int i = 2; i <= min; i++) {
if(x % i == 0 && y % i == 0) {
res = i;
}
}
return res;
}
更相减损法
public int gcd(int x, int y) {
while(x != y) {
if(x > y) {
x -= y;
}else {
y -= x;
}
}
return x;
}
辗转相除法(使用频率比较高)
public int gcd(int x, int y) {
return y == 0 ? x : gcd(y, x % y);
}
4. 最小公倍数
最小公倍数为两数之积除以其最大公约数
public int lcm(int x, int y) {
return (int)((long)x * y / gcd(x, y));
}
5. 摩尔投票法
算法解决的问题是如何在任意多的候选人(选票无序),选择获取票数最多的那个,即求众数
- 在任何数组中,出现次数大于该数组长度一半的值只能有一个
- 在任何数组中,出现次数大于该数组长度1/3的数最多有2个
leetcode:169. 多数元素
【解题思路】遇到相同的数,就投1票;遇到不同的数,就减1票,若当前候选数票数为0,则更新候选数,最后还存在票的数就是众数。
public int majorityElement(int[] nums) {
int res = Integer.MIN_VALUE, count = 0;
for(int x : nums) {
if(x == res) {
count++;
}else {
count--;
if(count <= 0) {
res = x;
count = 1;
}
}
}
return res;
}
leetcode:229. 多数元素 II
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素
【解题思路】使用两个变量one和two,和两个计数变量count1和count2,投票之后重新遍历数组看one和two的出现次数是否大于n/3。
6. 费马平方和定理
一个非负整数c能够表示为两个整数的平方和,当且仅当c的所有形如4k+3的质因子的幂次均为偶数。
或:自然数n可以表示为两个平方数之和等价于n的每个形如p=4m+3的素因子的幂次为偶数。
leetcode:633. 平方数之和
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a^2 + b^2 = c
public boolean judgeSquareSum(int c) {
int count, x;
for(int i = 2; i <= Math.sqrt(c); i++) {
if(c % i == 0) {
count = 0;
while(c % i == 0) {
count++;
c /= i;
}
if(i % 4 == 3 && count % 2 != 0) {
return false;
}
}
}
return c % 4 != 3;
}