欧拉函数
在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(因此φ(1)=1)。此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。 从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明。 欧拉函数-百度百科.
算法求解思想
欧拉函数具有以下性性质,以下性质是我们求解算法的依据:
- 当n=1时,n的欧拉函数Q(n)=1,n>1时,Q(n)的值位1~n之间与n互素的正整数个数
- 当n>1时,将n分解为素因数乘积的形式:n=p1t1p2t2…pktk,基于此,欧拉函数可表示为: Q ( n ) = n ∗ ∏ i = 1 k ( 1 − 1 p i ) Q(n)=n*\prod_{i=1}^k(1- \frac{1}{p_i}) Q(n)=n∗i=1∏k(1−pi1)
- 设n为素数,设n=p,则Q(n)=p-1
- 若n=pm(p为素数,m>1),则Q(n)=pm-1(p-1)
- 若n=p*q(p,q均为素数),则Q(n)=(p-1)(q-1)
本算法先将待求数进行素因式分解,利用HashMap进行因式去重,使用性质1和2来进行欧拉函数的求解。
代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
public class EulerFunction {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int temp =(int)EulerGenerate(n);//由于double运算的精度很高(64位存储),所以误差很小,导致小数部分很小,可以直接舍弃小数部分
System.out.println(temp);
}
private static double EulerGenerate(int n) {
if(n==1) {
return 1.0;
}
int eNum = -1;
String[] dc = Discompose(n).split(" ");
Map<Integer,Integer> map=new HashMap<>();//键表示素因数,值表示该素因数的次方数
for (String child : dc) {
int num=Integer.parseInt(child);//将每个素因数转化为整型(Discompose方法返回格式固定,略去异常处理)
if(map.containsKey(num)) {
map.put(num, map.get(num)+1);//把次方数加1
}else {
map.put(num, 1);
}
}
//System.out.println(map);
Set<Integer> set = map.keySet();
double temp=1.0;
for (Integer p : set) {
temp=temp*(1-(1.0/p));//直接使用double代替分数近似运算,在主函数中采用舍弃法处理误差
}
temp*=n;
return temp;
}
//对n进行素因式分解
private static String Discompose(int n) {
StringBuffer sb = new StringBuffer();
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
sb.append(i + " ");
n = n/i;
i--;
}
}
sb.append(n+" ");
return sb.toString();
}
}