2.5亿个整数中找出不重复的整数

本文介绍了一种利用2-Bitmap数据结构处理2.5亿个整数中不重复整数的方法,通过仅使用1GB内存实现高效的数据去重。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。


思路:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。扫描后,查看bitmap,把对应位是01的整数输出即可。



<think>好的,我现在需要解决这个问题:求两个正整数的最大公约数和最小公倍数。用户已经给出了输入样例是9和21,输出分别是3和63。我需要先理解问题,然后找出解决的方法,最后用C语言实现。 首先,最大公约数(GCD)是什么?GCD是两个数都能整除的最大的正整数。比如9和21,它们的公约数有1和3,所以最大的就是3。最小公倍数(LCM)则是能够同时被这两个数整除的最小的正整数,比如9和21的最小公倍数是63。 那怎么计算GCD和LCM呢?对于GCD,常用的方法是欧几里得算法,也就是辗转相除法。这个方法的步骤是:用较大的数除以较小的数,然后用余数替换较大的数,重复这个过程直到余数为零,此时较小的数就是GCD。比如,计算21和9的GCD: 21 ÷ 9 = 2余3 9 ÷ 3 = 3余0,所以GCD是3。 对于LCM,有一个公式可以利用GCD来计算:LCM(a, b) = (a × b) / GCD(a, b)。所以只要先算出GCD,就能很快得到LCM。例如,9和21的乘积是189,除以GCD3,得到63,就是LCM。 那现在我需要把这些步骤转化为C语言代码。首先,输入两个整数M和N。然后计算它们的GCD,再用公式求LCM。注意输入的M和N可能大小顺序确定,所以在用欧几里得算法时,要确保处理正确的顺序,或者在算法中自动调整。 另外,要注意处理余数的问题。比如在辗转相除的时候,可能需要交换数值。例如,当M小于N时,先交换它们的位置,或者直接用循环处理。这里可以用交换,因为即使M小于N,第一次计算余数后就会自动调整。 具体实现步骤: 1. 读取输入的两个整数M和N。 2. 使用欧几里得算法计算它们的GCD: a. 当N等于0时,重复以下步骤: i. 计算M除以N的余数R。 ii. 将M设为N,N设为R。 b. 当N为0时,M就是GCD。 3. 计算LCM:用原来的两个数相乘再除以GCD。 4. 输出GCD和LCM。 需要注意的是,原来的M和N在计算GCD的过程中会被修改,所以需要提前保存它们的原始值,用于计算LCM。例如,在代码中,可以先保存它们的乘积,或者在计算GCD之前复制一份原始值。 举个例子,假设输入是9和21: - 计算GCD时,初始M=21,N=9。余数R=21%9=3。然后M=9,N=3。再计算余数9%3=0,现在N=0,所以GCD是3。 - LCM就是9*21 /3 = 189/3=63。 那在代码中如何处理呢?比如,在计算GCD之前,先保存M和N的原始值,或者在计算的时候用临时变量。或者,在输入之后,将乘积保存下来,这样即使M和N在计算GCD时被改变,乘积仍然可以被使用。但需要注意,乘积可能很大,比如如果输入的是1000和1000,乘积是1,000,000,这在C语言中int类型是可以处理的,因为通常int是32位,最大到2^31-1,大约是20亿,所以没问题。 那现在编写代码的大致结构: - 输入M和N。 - 保存原始M和N,或者保存它们的乘积。 - 计算GCD。 - 计算LCM = (原始M * 原始N) / GCD。 - 输出GCD和LCM。 可能的错误点: 1. 没有保存原始的M和N,导致计算LCM的时候用了已经被修改的值。例如,在计算GCD的过程中,M和N的值会被改变,所以必须在计算GCD之前保存它们的原始值。 例如,在代码中,用户输入了a和b,然后计算它们的GCD。在计算过程中,a和b的值会被修改,所以在计算之前需要保存它们的值,比如用变量original_a = a, original_b = b,或者在输入的时候就把它们的乘积保存下来。 例如: int m, n; scanf("%d %d", &m, &n); int product = m * n; // 计算gcd // 然后 lcm = product / gcd; 但这里有个问题,如果计算gcd的过程中m和n的值被改变,比如在辗转相除时m和n被交换,那么product的值会是原来的m*n,这没问题。例如,假设用户输入的是9和21,那么product是189,管之后m和n的值如何变化,这个乘积还是正确的,因为原来的两个数是9和21,它们的乘积变。所以在代码中,可以在输入之后立即计算product = m * n,然后用这个值除以gcd得到lcm。 所以,正确的步骤是: 1. 输入m和n。 2. 保存product = m * n。 3. 计算gcd,此时m和n的值会被修改。 4. lcm = product / gcd。 但要注意,如果gcd是0的话会出问题,但题目中说输入的是正整数,所以gcd至少是1,会出现除以0的情况。 现在编写代码的具体部分: 读取输入: int m, n; scanf("%d %d", &m, &n); 计算gcd: 使用循环或者递归。这里用循环实现欧几里得算法: int a = m, b = n; while (b != 0) { int temp = b; b = a % b; a = temp; } int gcd = a; 这样,当循环结束后,a的值就是gcd。因为每次循环中,a和b的值会被更新为之前的b和a%b,直到b为0。例如,初始a=21,b=9: 第一次循环:b=9,a%9=21%9=3,所以b=3,a=9。 第二次循环:b=3,9%3=0,所以b=0,循环结束。此时a=3,gcd是3。 此时,原来的m和n的值没有被改变吗?比如,初始时m=9,n=21。在代码中,a和b是m和n的副本吗? 是的,因为代码中将a初始化为m,b初始化为n,所以在循环中修改的是a和b的值,原来的m和n的值没有被改变。所以product = m * n是正确的。 例如,如果输入的是m=9,n=21,那么product是9*21=189。在计算gcd的过程中,a和b被修改,但m和n的值还是原来的,所以product是正确的。 然后计算lcm的时候,就是product / gcd = 189 /3 =63。 所以整个代码的流程没有问题。 那现在把这些步骤写成C语言代码: #include <stdio.h> int main() { int m, n; scanf("%d %d", &m, &n); int product = m * n; // 计算gcd int a = m, b = n; while (b != 0) { int temp = b; b = a % b; a = temp; } int gcd = a; int lcm = product / gcd; printf("%d\n%d\n", gcd, lcm); return 0; } 测试这个代码的话,输入9 21,应该输出3和63。其他测试用例比如: 输入6和8,gcd是2,lcm是24。 输入12和18,gcd是6,lcm是36。 输入5和7,gcd是1,lcm是35。 这些应该都正确。 所以这个方法是可行的。另外,有没有其他方法可以计算gcd?比如更相减损术,或者递归版本的欧几里得算法? 递归版本的gcd函数可以这样写: int gcd(int a, int b) { if (b == 0) return a; else return gcd(b, a % b); } 但题目可能希望用循环结构,或者用户可能更习惯循环的方式。过对于本题来说,无论是递归还是循环都是可以的。在这里,用循环可能更高效,且需要额外的函数调用。 所以最终的代码应该正确解决问题。</think>--- ### **解决思路** 要计算两个正整数的最大公约数(GCD)和最小公倍数(LCM),可以通过以下步骤实现: 1. **计算最大公约数(GCD)**:使用**欧几里得算法**(辗转相除法): - 用较大数除以较小数,取余数。 - 将较小数作为新的被除数,余数作为新的除数,重复直到余数为零。 - 最后的非零余数即为GCD。 2. **计算最小公倍数(LCM)**:利用公式 $LCM(a, b) = \frac{a \times b}{GCD(a, b)}$。 --- ### **C语言代码实现** ```c #include <stdio.h> int main() { int m, n; scanf("%d %d", &m, &n); int product = m * n; // 保存原始乘积 int a = m, b = n; // 欧几里得算法求GCD while (b != 0) { int temp = b; b = a % b; a = temp; } int gcd = a; int lcm = product / gcd; // 计算LCM printf("%d\n%d\n", gcd, lcm); return 0; } ``` --- ### **代码解释** 1. **输入处理**:读取两个正整数 `m` 和 `n`。 2. **保存乘积**:提前计算 `m * n` 的乘积,用于后续求LCM。 3. **求GCD**:通过循环实现欧几里得算法: - 每次将 `a` 设为当前的除数 `b`,`b` 设为余数 `a % b`。 - 当 `b` 为0时,`a` 即为GCD。 4. **求LCM**:利用公式 $LCM = \frac{m \times n}{GCD}$。 5. **输出结果**:依次输出GCD和LCM。 --- ### **输入输出示例** **输入**: ``` 9 21 ``` **输出**: ``` 3 63 ``` **解释**: - GCD(9, 21):21 ÷ 9 余3 → 9 ÷ 3 余0,GCD为3。 - LCM(9, 21):$(9 \times 21) / 3 = 63$。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值