最大公约数、最小公倍数,同余原理

最大公约数

概念

最大公约数(Greatest Common Divisor,GCD)指的是两个或多个整数共有约数中最大的一个。例如,12 和 18 的公约数有 1、2、3、6,其中最大的公约数是 6,所以 12 和 18 的最大公约数就是 6。

应用场景

在很多算法问题中都会用到最大公约数,比如分数化简、密码学中的一些算法等。在 Java 编程里,经常会遇到需要计算两个数最大公约数的情况。

计算方法 - 欧几里得算法(辗转相除法)

欧几里得算法是计算最大公约数最常用的方法,其核心原理是:两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数。用公式表示就是:,其中  表示求最大公约数, 表示取余运算。

最小公倍数

概念

最小公倍数(Least Common Multiple,LCM)是指两个或多个整数公有的倍数中最小的一个。例如,4 和 6 的公倍数有 12、24、36 等,其中最小的公倍数是 12,所以 4 和 6 的最小公倍数就是 12。

应用场景

在实际编程和数学问题中,最小公倍数常用于处理周期性事件的同步、分数的通分等问题。比如在安排多个周期性任务同时执行时,就可能需要计算它们周期的最小公倍数来确定下一次同时执行的时间。

与最大公约数的关系

两个数  和  的最小公倍数和最大公约数之间存在一个重要的关系:,即两个数的乘积等于它们的最小公倍数与最大公约数的乘积。利用这个关系,我们可以通过先计算最大公约数,再计算最小公倍数。

    public static long gcd(long a, long b) {
		return b == 0 ? a : gcd(b, a % b);
	}

	public static long lcm(long a, long b) {
		return (long) a / gcd(a, b) * b;
	}

1. 同余原理的背景介绍

同余的概念最早由德国数学家高斯在他的著作《算术研究》中提出。同余原理源于人们对整数性质和运算规律的深入探索,在日常生活和科学研究中,存在大量具有周期性和循环性的现象,同余原理为解决这类问题提供了强大的工具。

在古代,同余的思想就已经被应用于天文历法的计算。例如,在计算节气、朔望和年、月、日的循环周期时,需要对时间进行取模运算,以确定天体的位置和时间的对应关系。在密码学领域,同余原理是许多加密算法的基础,如 RSA 算法就广泛运用了同余的性质来实现信息的加密和解密。在计算机科学中,同余原理也被用于数据的存储、哈希函数的设计以及算法的优化等方面。

2. 同余原理在加、减、乘运算中的应用

加法同余

这意味着在进行加法运算时,我们可以先对参与运算的数分别取模,然后将取模后的结果相加,最后再对相加的结果取模,其结果与直接对两数之和取模是相同的。这样做的好处是可以避免在计算过程中出现非常大的数,从而减少计算量和溢出的风险。

public class AdditionCongruence {
    public static void main(String[] args) {
        int a = 17;
        int b = 23;
        int m = 10;

        // 先计算和再取模
        int result1 = (a + b) % m;

        // 先分别取模再相加后取模
        int result2 = ((a % m) + (b % m)) % m;

        System.out.println("先求和再取模结果: " + result1);
        System.out.println("先分别取模再相加后取模结果: " + result2);
    }
}
乘法同余

同样地,在进行乘法运算时,我们可以先对参与运算的数分别取模,然后将取模后的结果相乘,最后再对相乘的结果取模。

public class MultiplicationCongruence {
    public static void main(String[] args) {
        int a = 17;
        int b = 23;
        int m = 10;

        // 先计算乘积再取模
        int result1 = (a * b) % m;

        // 先分别取模再相乘后取模
        int result2 = ((a % m) * (b % m)) % m;

        System.out.println("先求积再取模结果: " + result1);
        System.out.println("先分别取模再相乘后取模结果: " + result2);
    }
}
减法同余

对于减法运算,但在实际编程中,为了避免出现负数结果,我们通常使用 (a-b+m)%m 来确保结果是非负的。

public class SubtractionCongruence {
    public static void main(String[] args) {
        int a = 17;
        int b = 23;
        int m = 10;

        // 先计算差再取模
        int result1 = (a - b + m) % m;

        // 先分别取模再相减后取模
        int result2 = ((a % m) - (b % m) + m) % m;

        System.out.println("先求差再取模结果: " + result1);
        System.out.println("先分别取模再相减后取模结果: " + result2);
    }
}

3. 避免溢出问题

在进行乘法运算时,由于两个数相乘可能会超出整数类型的表示范围,导致溢出问题。为了避免这种情况,我们通常使用 long 类型作为中间变量来存储中间结果,在完成计算后再对结果取模并转换为所需的整数类型。

public class AvoidOverflow {
    public static void main(String[] args) {
        int a = 100000;
        int b = 100000;
        int m = 1000000007;

        // 使用 long 类型避免溢出
        long temp = (long) a * b;
        int result = (int) (temp % m);

        System.out.println("乘法结果取模: " + result);
    }
}

相应题目链接

878. 第 N 个神奇数字 - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值