质数、质因数、约数相关的java算法实现

基本概念

 因子/约数:因数是指整数a除以整数b(b≠0) 的商正好是整数而没有余数,我们就说b是a的因数。
 公约数:如果一个整数同时是几个整数的约数/因子,称这个整数为它们的公因数;
 最大公约数:公约数中最大的称为最大公约数
 质数:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
 自然数:非负整数。

质数

判断一个数是不是质数:

 暴力遍历:

public static boolean isPrime1(int prime) {
    //for (int i = 2; i <= prime; i++) 全部遍历
    /*
      由于质数可以变成2个因子的乘,那么如果一个因子大于sqrt(x)
       则另外一个小于sqrt(x),或者2个都是sqrt(x)
    */
   for (int i = 2; i <= Math.sqrt(prime); i++)
        if (prime % i == 0)
            return false;
   return true;
}

一个数不能被2整除,那么这个数一定不能被其他偶数整除,

 优化:

    public static boolean isPrime2(int prime) {
        if (prime <= 3)
            return prime > 1;
        if (prime % 2 == 0)
            return false;
        for (int i = 3; i <= Math.sqrt(prime); i += 2)
            if (prime % i == 0)
                return false;
        return true;
    }
(大于等于5的)质数一定和6的倍数相邻,一个是6x-1或6x+1
又因为6x-2/4一定能被2整除(2(x-1))
6x-3一定能被3整除
所以在1-6里面2,3,4,6都是不行的只有1和5可以

 代码再次优化:

    public static boolean isPrime(int prime) {
        if (prime <= 3)
            return prime > 1;
        if (prime % 6 != 1 && prime % 6 != 5)
            return false;
        for (int i = 5;  i <= Math.sqrt(prime); i += 6) // 乘法比除法快所以用i*i
            if (prime % i == 0 || prime % (i + 2) == 0)
                return false;
        return true;
    }

埃式筛法

判断一个数是不是不建议用这个方法

下文有具体介绍

求范围内的质数:

emm,可以知道的只有偶数(除了2)不是。所以外循环可以优化为

代码

/**
 * 返回范围内的质数数量
 * @param start
 * @param end
 * @return
 */
public static long countPrime(int start, int end){
    int i =start,count = 0;
    for (; i < end; i++)
        if (isPrime(i))
            count++;
    return count;
}

/**
 * 返回0-指定数的质数数量
 * @param end
 * @return
 */
public static long countPrime(int end){
    if (end < 4)
        return end - 1;
    return 2+countPrime(5,end);
}

埃式筛法

埃拉托色尼筛法(Sieve of Eratosthenes)是一种用于查找素数的简单而古老的算法。算法步骤如下:

  1. 创建一个长度为 n n n + 1 1 1 的布尔类型数组 i s p r i m e is_prime isprime,并将所有元素初始化为 t r u e true true
  2. 设置 i s _ p r i m e is\_prime is_prime [ 0 0 0 ]和 i s _ p r i m e is\_prime is_prime [ 1 1 1 ]为 f a l s e false false ,因为 0 0 0 1 1 1 不是素数。
  3. 2 2 2 开始循环到 s q r t sqrt sqrt { n n n },如果 i s _ p r i m e is\_prime is_prime [ i i i ]为 t r u e true true ,则将 i i i 的所有倍数(除了 i i i 本身)标记为 f a l s e false false ,即设置 i s _ p r i m e is\_prime is_prime [ j j j ]= f a l s e false false ( j j j = i i i , i i i ( i i i + 1 1 1 ), i i i *( i i i + 2 2 2 )… 直到 j j j > n n n ).
  4. 遍历 i s _ p r i m e is\_prime is_prime []数组,将值为 t r u e true true 的下标存储到另一个数组 p r i m e s primes primes []中,这样就得到了从 2 2 2 n n n 之间的所有素数。

时间复杂度为 O ( n log ⁡ log ⁡ n ) O(n\log{\log{n}}) O(nloglogn),空间复杂度为 O ( n ) O(n) O(n)

	public ArrayList<Integer> getPrimes(int n){
        ArrayList<Integer> primes = new ArrayList<>();
        boolean[] f = new boolean[n+1];
        for (int i = 2; i < n + 1; i++) {
            if (!f[i]){
                primes.add(i);
                for (int j = i+i; j < n + 1; j+=i) {
                    f[j] = true;
                }
            }
        }
        return primes;
    }

合数

非质数就是合数

质因数

质因数(素因数或质因子)在数论里是指能整除给定正整数的质数。
除了1以外,两个没有其他共同质因子的正整数称为互质。

正整数的因数分解可将正整数表示为一连串的质因子相乘,质因子如重复可以用指数表示。

根据算术基本定理,任何正整数皆有独一无二的质因子分解式  。

质数只有一个质因子就是本身。

分解质因数

    public ArrayList<Integer> zhiyin(int n){
        ArrayList<Integer> a = new ArrayList<>();
        for (int i = 2; i <= n; i++) {
            while (n % i == 0) {
                a.add(i);
                n /= i;
            }
        }
        return a;
    }

约数

约数,又称因数。整数a除以整数b(b≠0)除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a。a称为b的倍数,b称为a的约数。

判断约数数量

约数个数定理是指:一个正整数N可以分解为质因数乘积 N = p 1 a 1 ⋅ p 2 a 2 ⋅ . . . ⋅ p k a k N=p_1^{a_1} \cdot p_2^{a_2} \cdot ... \cdot p_k^{a_k} N=p1a1p2a2...pkak,其中 p 1 , p 2 , . . . , p k p_1,p_2,...,p_k p1,p2,...,pk为不同的质数, a 1 , a 2 , . . . , a k a_1,a_2,...,a_k a1,a2,...,ak为正整数,则N的约数个数为 ( a 1 + 1 ) ⋅ ( a 2 + 1 ) ⋅ . . . ⋅ ( a k + 1 ) (a_1+1)\cdot(a_2+1)\cdot...\cdot(a_k+1) (a1+1)(a2+1)...(ak+1)个。

数学公式为:
d ( N ) = ( a 1 + 1 ) ⋅ ( a 2 + 1 ) ⋅ . . . ⋅ ( a k + 1 ) \large{d(N) = (a_1+1)\cdot(a_2+1)\cdot...\cdot(a_k+1)} d(N)=(a1+1)(a2+1)...(ak+1)

其中, d ( N ) d(N) d(N)表示N的约数个数。

分解质因数方法

public static long countDivisor(long divisor){
    long count = 1;
    for (long i = 2; i*i <= divisor; i++) {
        long numi = 0;
        while (divisor % i == 0){
            numi++;
            divisor/=i;
        }
        count*=numi+1;
    }if (divisor > 1)
         count*=2;
    return count;
}

暴力

public static int countDivisor1(int divisor) {
    int count = 0;
    int i = 1;
    /*for (int i = 1; i <= divisor; i++)
        if (divisor % i == 0)
            count++;*/
    for (; i*i < divisor; i++)
        if (divisor % i == 0)
            count+=2;
    return i*i==divisor?count+1:count;}

最小公倍数

如求 a a a b b b 的最小公倍数。
则最小公倍数等于 a ∗ b / g c b ( a , b ) a*b/gcb(a,b) ab/gcb(a,b)

2个数的乘积除以这2个数的最大公约数
    public BigInteger aaa(int a,int b){
        BigInteger bi = BigInteger.valueOf(a);
        BigInteger bb = BigInteger.valueOf(b);
        return bi.multiply(bb)
                .divide(bi.gcd(bb));
    }

最大公约数

api

java可以直接使用api进行求解

    public BigInteger aaa(int a,int b){
        return BigInteger.valueOf(a).gcd(BigInteger.valueOf(b));
    }

暴力获取

int big = Math.max(a, b);
int small = Math.min(a, b);
if (big % small == 0)
    return small;
for (int i = small / 2; i > 1; i--) {
    if (big % i == 0 && small % i == 0) 
        return i;    
}
return 1;

辗转相除法(欧几里德算法)

实现

int result = 0;
while (n != 0) {
    result = m % n;
    m = n;
    n = result;
}
return m;

递归实现

public static int gcd (int a,int b) {
    if(b==0)
        return a;
    else
        return gcd(b,a%b);
}

更相减损

实现

while(m != n) {
    if(m > n)
        m -= n;
    else
        n-= m;
}
return m;

递归

public static int gcd (int a,int b) {
    if (a==b) 
        return a;
    else if (a>b)
      a = a-b;    
    else
       b = b-a;
    return gcd(a, b);
}

互质

2个数互质,说明其最大公约数为1

static int gcd(int a, int b) {
        if (a % b == 0)
            return b;
        return gcd(b, a % b);
    }

习题

质数

蓝桥杯–超级质数
蓝桥杯–最大和

待补充
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《妙趣横生的算法(C语言实现)》可作为算法入门人员的教程,也可以作为学习过C语言程序设计的人士继续深造的理想读物,也可作为具有一定经验的程序设计人员巩固和提高编程水平,查阅相关算法实现数据结构知识的参考资料,同时也为那些准备参加与算法数据结构相关的面试的读者提供一些有益的帮助。最大的特色在于实例丰富,题材新颖有趣,实用性强,理论寓于实践之中。理论与实践相结合,旨在帮助读者理解算法,并提高C语言编程能力,培养读者的编程兴趣,并巩固已有的C语言知识。全书分为2个部分共10章,内容涵盖了编程必备的基础知识(如数据结构、常用算法等),编程实例介绍,常见算法数据结构面试题等。可以使读者开阔眼界,提高编程的兴趣,提高读者的编程能力和应试能力。 目录: 第1部分 基础篇 第1章 数据结构基础 1.1 什么是数据结构 1.2 顺序表 1.2.1 顺序表的定义 1.2.2 向顺序表中插入元素 1.2.3 从顺序表中删除元素 1.2.4 实例与分析 1.3 链表 1.3.1 创建一个链表 1.3.2 向链表中插入结点 1.3.3 从链表中删除结点 1.3.4 销毁一个链表 1.3.5 实例与分析 1.4 栈 1.4.1 栈的定义 1.4.2 创建一个栈 1.4.3 入栈操作 1.4.4 出栈操作 1.4.5 栈的其他操作 1.4.实例与分析 1.5 队列 1.5.1 队列的定义 1.5.2 创建一个队列 1.5.3 入队列操作 1.5.4 出队列操作 1.5.5 销毁一个队列 1.5.6 循环队列的概念 1.5.7 循环队列的实现 1.5.8 实例与分析 1.6 树结构 1.6.1 树的概念 1.6.2 树结构的计算机存储形式 1.6.3 二叉树的定义 1.6.4.二叉树的遍历 1.6.5 创建二叉树 1.6.6 实例与分析 1.7 图结构 1.7.1 图的概念 1.7.2 图的存储形式 1.7.3 邻接表的定义 1.7.4.图的创建 1.7.5 图的遍历(1)——深度优先搜索 1.7.6 图的遍历(2)——广度优先搜索 1.7.7 实例与分析 第2章 常用的查找与排序方法 2.1 顺序查找 2.2 折半查找 2.3 排序的概述 2.4 直接插入排序 2.5 选择排序 2.6 冒泡排序 2.7 希尔排序 2.8 快速排序 第3章 常用的算法思想 3.1 什么是算法 3.2 算法的分类表示及测评 3.2.1 算法的分类 3.2.2 算法的表示 3.2.3 算法性能的测评 3.3 穷举法思想 3.3.1 基本概念 3.3.2 寻找给定区间的素数 3.3.3 TOM的借书方案 3.4 递归与分治思想 3.4..1 基本概念 3.4.2 计算整数的划分数 3.4.3 递归的折半查找算法 3.5 贪心算法思想 3.5.1 基本概念 3.5.2 最优装船问题 3.6 回溯法 3.6.1 基本概念 3.6.2 四皇后问题求解 3.7 数值概率算法 3.7.1 基本概念 3.7.2 计算定积分 第2部分 编程实例解析 第4章 编程基本功 4.1 字符类型统计器 4.2 计算字符的ASCII码 4.3 嵌套if.else语句的妙用 4.4 基于switch语句的译码器 4.5 判断闰年 4.6 指针变量作参数 4.7 矩阵的转置运算 4.8 矩阵的乘法运算 4.9 巧用位运算 4.10 文件的读写 4.11 计算文件的大小 4.12 记录程序的运行时间 4.13 十进制/二进制转化器 4.14 打印特殊图案 4.15 打印杨辉三角 4.16 复杂级数的前n项和 4.17 寻找矩阵中的“鞍点” 4.18 n阶勒让德多项式求解 4.19 递归反向输出字符串 4.20 一年中的第几天 第5章 数学趣题(一) 5.1 舍罕王的失算 5.2 求两个数的最大公约数和最小公倍数 5.3 歌德巴赫猜想的近似证明 5.4 三色球问题 5.5 百钱买百鸡问题 5.6 判断回文数字 5.7 填数字游戏求解 5.8 新郎和新娘 5.9 爱因斯坦的阶梯问题 5.10 寻找水仙花数 5.11 猴子吃桃问题 5.12 兔子产仔问题 5.13 分解质因数 5.14 常胜将军 5.15 求兀的近似值 5.16 魔幻方阵 5.17 移数字游戏 5.18 数字的全排列 5.19 完全数 5.20 亲密数 5.21 数字翻译器 5.22 递归实现数制转换 5.23 谁在说谎 第6章 数学趣题(二) 6.1 连续整数固定和问题 6.2 表示成两个数的平方和 6.3 具有特殊性质的数 6.4 验证角谷猜想 6.5 验证四方定理 6.6 递归法寻找最小值 6.7 寻找同构数 6.8 验证尼科彻斯定理 6.9 三重回文数字 6.10 马克思手稿中的数学题 6.11 渔夫捕鱼问题 6.12 寻

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小余

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值