【888题秋招篇】剑指大厂offer第七题,带你用枚举优化方法秒杀腾讯校招真题-最大公约数,斩获大厂年薪60wOffer

更多精彩内容

这里是带你游历编程世界的Dashcoding编程社,我是Dash/北航硕士/ICPC区域赛全国排名30+/给你呈现我们眼中的世界!

256题算法特训课,帮你斩获大厂60W年薪offer

原题

腾讯校招真题最大公约数

B站动画详解

问题分析

这道题的核心在于通过有限的 k k k 次操作,最大化两个整数 a a a b b b 的最大公约数 (GCD, Greatest Common Divisor)。具体来说,问题要求每次可以将 a a a b b b 增加1,然后问在进行 k k k 次操作后,如何使 a a a b b b 的 GCD 最大。GCD 的性质决定了当两个数之间差距越小且有更多的公共因子时,GCD 越大。因此,最优策略是通过调整 a a a b b b 的值来找到差距最小且GCD最大的情况。

在实际操作中,可以枚举每一种可能的操作组合,即 a + i a + i a+i b + ( k − i ) b + (k - i) b+(ki),其中 i i i 代表对 a a a 进行的自增次数, k − i k - i ki 代表对 b b b 进行的自增次数。对每种组合计算 GCD 并取最大值即为所求。

为了优化计算过程,可以利用欧几里得算法快速计算两个数的 GCD,从而确保在枚举所有可能操作组合时,效率仍然较高。

思路分析

这道题的解法主要依赖枚举优化和GCD的性质。具体实现思路如下:

  1. 枚举 i i i 的取值范围从 0 0 0 k k k,表示对 a a a 进行了 i i i 次自增。
  2. 对于每个 i i i,计算 a + i a + i a+i b + ( k − i ) b + (k - i) b+(ki) 的 GCD。
  3. 在所有枚举的结果中,取最大的 GCD 即为答案。
    这个算法的核心是利用了GCD的性质,以及对 k k k 次操作进行枚举。尽管最坏情况下需要枚举 k + 1 k + 1 k+1 种情况,但由于 k k k 的最大值为 100 , 000 100,000 100,000,而 GCD 的计算效率很高 (时间复杂度为 O ( log ⁡ ( min ⁡ ( a , b ) ) ) O(\log(\min(a, b))) O(log(min(a,b)))),因此整体算法在常数因子较低的情况下仍然可以通过。

算法的时间复杂度为 O ( T × k × log ⁡ ( min ⁡ ( a , b ) ) ) O(T \times k \times \log(\min(a, b))) O(T×k×log(min(a,b))),其中 T T T 是测试用例的数量。尽管 k k k 的范围较大,但在合理的优化下,算法在规定的输入范围内仍然能保证较快的执行速度。

算法实现

代码主要分为两部分:首先定义了一个用于计算 GCD 的函数 gcd(int a, int b),该函数采用欧几里得算法,通过不断取余直到余数为 0 来获取 GCD。接着在主函数中,读取测试用例的数量 t t t 并逐个处理。

对于每个测试用例,读取 a a a b b b k k k 的值,并通过循环枚举所有可能的 i i i。对于每种 i i i,计算 a + i a + i a+i b + ( k − i ) b + (k - i) b+(ki) 的 GCD,并在结果中选择最大值。

最后输出每个测试用例的结果。

代码详解

标准代码程序

C++代码

#include <iostream>
using namespace std;

int gcd(int a, int b)
{
    while (b != 0)
    {
        int tmp = a;
        a = b;
        b = tmp % b;
    }
    return a;
}

int main()
{
    int t;
    cin >> t;
    for (int i = 0; i < t; ++i)
    {
        int a, b, k;
        cin >> a >> b >> k;
        int ans = 0;
        for (int i = 0; i < k; ++i)
        {
            ans = max(gcd(a + i, b + k - i), ans);
        }
        cout << ans << "\n";
    }
    return 0;
}

Java代码

import java.util.Scanner;

public class Main {
    public static int gcd(int a, int b) {
        while (b != 0) {
            int tmp = a;
            a = b;
            b = tmp % b;
        }
        return a;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();
        for (int i = 0; i < t; ++i) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int k = scanner.nextInt();
            int ans = 0;
            for (int j = 0; j < k; ++j) {
                ans = Math.max(gcd(a + j, b + k - j), ans);
            }
            System.out.println(ans);
        }
        scanner.close();
    }
}

Python代码

import math

def solve():
    t = int(input())
    for _ in range(t):
        a, b, k = map(int, input().split())
        ans = 0
        for i in range(k):
            ans = max(math.gcd(a + i, b + k - i), ans)
        print(ans)

if __name__ == "__main__":
    solve()

Javascript代码

function gcd(a, b) {
    while (b !== 0) {
        let tmp = a;
        a = b;
        b = tmp % b;
    }
    return a;
}

function solve() {
    const input = require('readline').createInterface({
        input: process.stdin,
        output: process.stdout
    });

    let t = null;
    const data = [];
    input.on('line', (line) => {
        if (t === null) {
            t = parseInt(line);
        } else {
            data.push(line.split(' ').map(Number));
            if (data.length === t) {
                input.close();
            }
        }
    });

    input.on('close', () => {
        data.forEach(([a, b, k]) => {
            let ans = 0;
            for (let i = 0; i < k; i++) {
                ans = Math.max(gcd(a + i, b + k - i), ans);
            }
            console.log(ans);
        });
    });
}

solve();

复杂度分析

时间复杂度分析

给定测试用例数量 T T T、两个整数 a a a b b b 以及操作次数 k k k,算法的核心是枚举从 i = 0 i = 0 i=0 i = k i = k i=k 的所有可能操作组合。对于每一个操作组合,我们都需要计算两个数的最大公约数(GCD)。因此,算法的时间复杂度主要由以下几部分组成:

  1. 枚举操作组合的复杂度:算法需要枚举 i i i 0 0 0 k k k 的所有值,所以这一部分的时间复杂度是 O ( k ) O(k) O(k)

  2. GCD 计算的复杂度:对于每个枚举的组合,需要计算 a + i a + i a+i b + ( k − i ) b + (k - i) b+(ki) 的 GCD。使用欧几里得算法计算 GCD 的时间复杂度是 O ( log ⁡ ( min ⁡ ( a , b ) ) ) O(\log(\min(a, b))) O(log(min(a,b)))

  3. 总复杂度:在最坏情况下,测试用例数量 T T T 20 20 20,每个测试用例中 k k k 的最大值是 100 , 000 100,000 100,000。因此,总时间复杂度是 O ( T × k × log ⁡ ( min ⁡ ( a , b ) ) ) O(T \times k \times \log(\min(a, b))) O(T×k×log(min(a,b)))。用具体的值替代表示,总复杂度最多为 O ( 20 × 100 , 000 × log ⁡ ( 100 , 000 ) ) O(20 \times 100,000 \times \log(100,000)) O(20×100,000×log(100,000)),大约为 O ( 20 × 100 , 000 × 17 ) = 34 , 000 , 000 O(20 \times 100,000 \times 17) = 34,000,000 O(20×100,000×17)=34,000,000 次操作。

虽然计算量较大,但由于 GCD 计算的效率较高(欧几里得算法的常数因子很小),在规定的输入范围内,这个复杂度是可以接受的,尤其在 C++、Java 等高效语言中。

空间复杂度分析

空间复杂度主要考虑算法在执行过程中使用的额外内存,包括变量、数据结构、递归调用栈等。

  1. 输入数据占用的空间:算法中需要存储 T T T 组测试用例,每个测试用例包含 a a a b b b k k k 这三个整数。因为 T T T 的最大值是 20,整数的大小为 O ( 1 ) O(1) O(1),所以这部分的空间复杂度是 O ( T ) O(T) O(T),在最坏情况下是 O ( 20 ) O(20) O(20),这属于常量级别的空间占用。

  2. 枚举操作时的临时变量:在枚举 i i i 的过程中,主要存储的是中间结果 a + i a + i a+i b + ( k − i ) b + (k - i) b+(ki) 以及计算得到的 GCD 值。这些都是固定的整数,占用常量级别的空间,因此这一部分的空间复杂度是 O ( 1 ) O(1) O(1)

  3. GCD 计算的空间:欧几里得算法的 GCD 计算是一个递归过程,但在实际实现中通常使用迭代版本,递归深度为 O ( log ⁡ ( min ⁡ ( a , b ) ) ) O(\log(\min(a, b))) O(log(min(a,b))),也就是说,GCD 计算的空间复杂度为 O ( log ⁡ ( min ⁡ ( a , b ) ) ) O(\log(\min(a, b))) O(log(min(a,b)))。但是因为我们采用了迭代方法,实际上没有额外的递归栈空间,所以这部分的空间占用也只是 O ( 1 ) O(1) O(1)

  4. 输出数据的空间:输出每个测试用例的结果是一个整数,因此总共输出 T T T 个结果,占用 O ( T ) O(T) O(T) 的空间,最坏情况下为 O ( 20 ) O(20) O(20),仍然是常量级别的。

总结

这道题目要求通过最多 k k k 次操作来最大化两个整数 a a a b b b 的最大公约数(GCD)。为了实现这一目标,算法采用了枚举优化的策略,通过遍历每一种可能的操作组合(即 a + i a + i a+i b + ( k − i ) b + (k - i) b+(ki)),计算相应的 GCD,并选择最大的结果作为最终答案。

在算法分析中,我们得出了时间复杂度为 O ( T × k × log ⁡ ( min ⁡ ( a , b ) ) ) O(T \times k \times \log(\min(a, b))) O(T×k×log(min(a,b))),其中 T T T 是测试用例的数量, k k k 是允许的操作次数, log ⁡ ( min ⁡ ( a , b ) ) \log(\min(a, b)) log(min(a,b)) 是计算 GCD 的复杂度。虽然 k k k 的最大值达到 100,000,但由于欧几里得算法计算 GCD 的效率极高,因此在实际输入范围内,该算法的运行效率可以接受。

空间复杂度方面,由于算法中只使用了少量的额外空间,主要是常量级别的变量,因此空间复杂度为 O ( 1 ) O(1) O(1),除去输入输出外不需要额外的内存。

综上所述,这道题的解法不仅简洁有效,且在高效实现下可以处理大规模输入。对于需要在有限操作次数内寻找最优解的问题,这样的枚举优化策略是十分值得参考的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值