【饿了么笔试题汇总】2024-03-24-饿了么春招笔试题

🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员

✨ 本系列打算持续跟新饿了么近期的春秋招笔试题汇总~

💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导

👏 感谢大家的订阅➕ 和 喜欢💗

01.K小姐的魔法大冒险

问题描述

K小姐正在玩一款魔法冒险游戏。游戏中有 n n n 只怪物,每只怪物有自己的血量上限 h i h_i hi。初始时,所有怪物的血量都等于它们的血量上限。当一只怪物的血量小于等于 0 0 0 时,它就会死亡。

K小姐拥有两个强大的魔法技能:

  1. 魔法风暴:消耗 1 1 1 点魔法值,对所有存活的怪物造成 1 1 1 点伤害。
  2. 死亡之触:消耗 2 2 2 点魔法值,可以立即杀死一只已经受伤的怪物(即当前血量小于血量上限的怪物)。

这两个技能都可以使用任意次数。K小姐想知道,最少需要消耗多少魔法值,才能杀死所有怪物,成功通关。

输入格式

第一行包含一个正整数 n n n 2 ≤ n ≤ 1 0 5 2 \leq n \leq 10^5 2n105),表示怪物的数量。

第二行包含 n n n 个正整数 h 1 , h 2 , … , h n h_1, h_2, \ldots, h_n h1,h2,,hn 1 ≤ h i ≤ 1 0 9 1 \leq h_i \leq 10^9 1hi109),表示每只怪物的血量上限。

输出格式

输出一个整数,表示K小姐最少需要消耗的魔法值。

样例输入

3
1 1 4

样例输出

3

数据范围

  • 2 ≤ n ≤ 1 0 5 2 \leq n \leq 10^5 2n105
  • 1 ≤ h i ≤ 1 0 9 1 \leq h_i \leq 10^9 1hi109

题解

我们可以先对所有怪物使用魔法风暴,将它们的血量都减少 1 1 1。此时,血量上限为 1 1 1 的怪物就直接死亡了。

接下来,我们可以选择继续使用魔法风暴,或者对已经受伤的怪物使用死亡之触。我们可以计算出,如果我们连续使用魔法风暴,直到最高血量的怪物血量减少到 1 1 1 或以下,一共需要消耗的魔法值。与此同时,我们也可以计算出,如果我们对所有已经受伤的怪物使用死亡之触,一共需要消耗的魔法值。

我们选择消耗魔法值较少的方案,直到所有怪物都被消灭。在样例中,使用 1 1 1 次魔法风暴和 2 2 2 次死亡之触,一共消耗 3 3 3 点魔法值,是最优解。

参考代码

  • Python
n = int(input())
h = list(map(int, input().split()))

h.sort()  # 将怪物按血量从低到高排序
ans = 1  # 初始消耗1点魔法值用于魔法风暴
zeros = h.count(1)  # 统计血量为1的怪物数量

for i in range(zeros, n):
    if (n - i) * 2 < h[i] - 1:
        # 如果对剩余怪物使用死亡之触的魔法值消耗小于
        # 将当前怪物血量降至1所需的魔法风暴次数,
        # 则对剩余怪物使用死亡之触
        ans += (n - i) * 2
        break
    else:
        # 否则,将当前怪物血量降至1,累计消耗的魔法值
        ans += h[i] - 1

print(ans)
  • Java
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] h = new int[n];
        for (int i = 0; i < n; i++) {
            h[i] = sc.nextInt();
        }
        
        Arrays.sort(h);  // 将怪物按血量从低到高排序
        int ans = 1;  // 初始消耗1点魔法值用于魔法风暴
        int zeros = 0;  // 统计血量为1的怪物数量
        for (int i = 0; i < n; i++) {
            if (h[i] == 1) {
                zeros++;
            }
        }
        
        for (int i = zeros; i < n; i++) {
            if ((n - i) * 2 < h[i] - 1) {
                // 如果对剩余怪物使用死亡之触的魔法值消耗小于
                // 将当前怪物血量降至1所需的魔法风暴次数,
                // 则对剩余怪物使用死亡之触
                ans += (n - i) * 2;
                break;
            } else {
                // 否则,将当前怪物血量降至1,累计消耗的魔法值
                ans += h[i] - 1;
            }
        }
        
        System.out.println(ans);
    }
}
  • Cpp
#include <iostream>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    int h[n];
    for (int i = 0; i < n; i++) {
        cin >> h[i];
    }
    
    sort(h, h + n);  // 将怪物按血量从低到高排序
    int ans = 1;  // 初始消耗1点魔法值用于魔法风暴
    int zeros = 0;  // 统计血量为1的怪物数量
    for (int i = 0; i < n; i++) {
        if (h[i] == 1) {
            zeros++;
        }
    }
    
    for (int i = zeros; i < n; i++) {
        if ((n - i) * 2 < h[i] - 1) {
            // 如果对剩余怪物使用死亡之触的魔法值消耗小于
            // 将当前怪物血量降至1所需的魔法风暴次数,
            // 则对剩余怪物使用死亡之触
            ans += (n - i) * 2;
            break;
        } else {
            // 否则,将当前怪物血量降至1,累计消耗的魔法值
            ans += h[i] - 1;
        }
    }
    
    cout << ans << endl;
    return 0;
}

02.LYA的宝石项链

问题描述

LYA喜欢收集各种漂亮的宝石。她有两条宝石项链,分别记为项链 A A A 和项链 B B B,每条项链都有 n n n 颗宝石。宝石有大有小,每颗宝石都有一个美丽值。

LYA想知道,如果从两条项链中分别选出一些宝石(保持宝石在项链中的相对顺序),使得选出的两组宝石的美丽值之和相等,那么一共有多少种选法。

输入格式

第一行包含一个正整数 n n n 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105),表示每条项链的宝石数量。

第二行包含 n n n 个正整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an 1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1ai109),表示项链 A A A 中每颗宝石的美丽值。

第三行包含 n n n 个正整数 b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,,bn 1 ≤ b i ≤ 1 0 9 1 \leq b_i \leq 10^9 1bi109),表示项链 B B B 中每颗宝石的美丽值。

输出格式

输出一个整数,表示选法的总数。由于答案可能很大,请输出答案对 1 0 9 + 7 10^9 + 7 109+7 取模的结果。

样例输入

3
1 2 3
3 2 1

样例输出

7

数据范围

  • 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105
  • 1 ≤ a i , b i ≤ 1 0 9 1 \leq a_i, b_i \leq 10^9 1ai,bi109

题解

本题可以使用哈希表来解决。我们先将两条项链中每颗宝石的美丽值相加,得到一个新的数组。然后我们统计这个新数组中每个美丽值出现的次数。

对于新数组中的每个美丽值,如果它出现了 k k k 次,那么我们可以从这 k k k 个位置中任意选择一些位置,使得选出的宝石的美丽值之和相等。这相当于从 k k k 个元素中选择任意个元素的方案数,即 2 k 2^k 2k

因此,我们只需要将所有美丽值的方案数相加,再减去空集的方案(即不选任何宝石的方案),就得到了最终的答案。

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)

参考代码

  • Python
MOD = 10**9 + 7

n = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))

cnt = {}
for i in range(n):
    s = a[i] + b[i]
    cnt[s] = cnt.get(s, 0) + 1

ans = 0
for k in cnt.values():
    ans = (ans + pow(2, k, MOD)) % MOD

print((ans - 1 + MOD) % MOD)
  • Java
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    static final int MOD = (int) 1e9 + 7;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        int[] b = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        for (int i = 0; i < n; i++) {
            b[i] = sc.nextInt();
        }

        Map<Integer, Integer> cnt = new HashMap<>();
        for (int i = 0; i < n; i++) {
            int s = a[i] + b[i];
            cnt.put(s, cnt.getOrDefault(s, 0) + 1);
        }

        long ans = 0;
        for (int k : cnt.values()) {
            ans = (ans + quickPow(2, k)) % MOD;
        }

        System.out.println((ans - 1 + MOD) % MOD);
    }

    static long quickPow(long x, int n) {
        long res = 1;
        while (n > 0) {
            if (n % 2 == 1) {
                res = res * x % MOD;
            }
            x = x * x % MOD;
            n /= 2;
        }
        return res;
    }
}
  • Cpp
#include <iostream>
#include <unordered_map>
using namespace std;

const int MOD = 1e9 + 7;

int quickPow(int x, int n) {
    int res = 1;
    while (n > 0) {
        if (n & 1) {
            res = 1LL * res * x % MOD;
        }
        x = 1LL * x * x % MOD;
        n >>= 1;
    }
    return res;
}

int main() {
    int n;
    cin >> n;
    int a[n], b[n];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }

    unordered_map<int, int> cnt;
    for (int i = 0; i < n; i++) {
        int s = a[i] + b[i];
        cnt[s]++;
    }

    int ans = 0;
    for (auto [_, k] : cnt) {
        ans = (ans + quickPow(2, k)) % MOD;
    }

    cout << (ans - 1 + MOD) % MOD << endl;
    return 0;
}

03.K小姐的魔法石分解

问题描述

K小姐是一位魔法师,她拥有许多魔法石。每个魔法石都有一个能量值,能量值等于它的正因子个数。

现在,K小姐想把一些魔法石分解成若干块(也可以不分解),但要满足以下条件:

  1. 分解后的每块魔法石的能量值必须大于 1 1 1
  2. 分解后的所有魔法石的能量值之积等于原魔法石的能量值。

K小姐想知道,对于给定的一块魔法石,如何分解可以使得分解后的所有魔法石的能量值之和最大。

输入格式

第一行包含一个正整数 T T T 1 ≤ T ≤ 1 0 4 1 \leq T \leq 10^4 1T104),表示测试数据组数。

接下来 T T T 行,每行包含一个正整数 x x x 2 ≤ x ≤ 2 × 1 0 5 2 \leq x \leq 2 \times 10^5 2x2×105),表示原魔法石的能量值。

输出格式

输出共 T T T 行,每行一个整数,表示对应测试数据中,分解后的所有魔法石能量值之和的最大值。

样例输入

3
2
10
123

样例输出

2
4
4

数据范围

  • 1 ≤ T ≤ 1 0 4 1 \leq T \leq 10^4 1T104
  • 2 ≤ x ≤ 2 × 1 0 5 2 \leq x \leq 2 \times 10^5 2x2×105

题解

本题可以使用质因数分解的方法来解决。对于给定的能量值 x x x,我们可以将其分解为若干个质因数的乘积,即 x = p 1 a 1 × p 2 a 2 × … × p k a k x = p_1^{a_1} \times p_2^{a_2} \times \ldots \times p_k^{a_k} x=p1a1×p2a2××pkak,其中 p i p_i pi 为质因数, a i a_i ai 为对应的指数。

对于每个质因数 p i p_i pi,它可以被分解成 1 1 1 a i a_i ai 块,每块的能量值都是 p i p_i pi。因此,对于原魔法石 x x x,我们可以将其分解成 ( a 1 + 1 ) × ( a 2 + 1 ) × … × ( a k + 1 ) (a_1 + 1) \times (a_2 + 1) \times \ldots \times (a_k + 1) (a1+1)×(a2+1)××(ak+1) 块,每块的能量值都是某个质因数的幂次。

最终,分解后的所有魔法石的能量值之和就是 ( a 1 + 1 ) × ( a 2 + 1 ) × … × ( a k + 1 ) (a_1 + 1) \times (a_2 + 1) \times \ldots \times (a_k + 1) (a1+1)×(a2+1)××(ak+1)

特别地,如果原魔法石 x x x 本身就是一个质数,那么最优的分解方案就是不分解,此时能量值之和为 2 2 2

时间复杂度为 O ( T x ) O(T \sqrt{x}) O(Tx ),空间复杂度为 O ( 1 ) O(1) O(1)

参考代码

  • Python
t = int(input())

for _ in range(t):
    x = int(input())
    
    factors = []
    i = 2
    while i * i <= x:
        if x % i == 0:
            cnt = 0
            while x % i == 0:
                cnt += 1
                x //= i
            factors.append((i, cnt))
        i += 1
    
    if x > 1:
        factors.append((x, 1))
    
    if len(factors) == 1:
        print(factors[0][1] * 2)
    else:
        ans = 1
        for _, cnt in factors:
            ans *= (cnt + 1)
        print(ans)
  • Java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        
        while (t-- > 0) {
            int x = sc.nextInt();
            
            List<int[]> factors = new ArrayList<>();
            int i = 2;
            while (i * i <= x) {
                if (x % i == 0) {
                    int cnt = 0;
                    while (x % i == 0) {
                        cnt++;
                        x /= i;
                    }
                    factors.add(new int[]{i, cnt});
                }
                i++;
            }
            
            if (x > 1) {
                factors.add(new int[]{x, 1});
            }
            
            if (factors.size() == 1) {
                System.out.println(factors.get(0)[1] * 2);
            } else {
                int ans = 1;
                for (int[] factor : factors) {
                    ans *= (factor[1] + 1);
                }
                System.out.println(ans);
            }
        }
    }
}
  • Cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int t;
    cin >> t;
    
    while (t--) {
        int x;
        cin >> x;
        
        vector<pair<int, int>> factors;
        int i = 2;
        while (i * i <= x) {
            if (x % i == 0) {
                int cnt = 0;
                while (x % i == 0) {
                    cnt++;
                    x /= i;
                }
                factors.emplace_back(i, cnt);
            }
            i++;
        }
        
        if (x > 1) {
            factors.emplace_back(x, 1);
        }
        
        if (factors.size() == 1) {
            cout << factors[0].second * 2 << endl;
        } else {
            int ans = 1;
            for (auto [_, cnt] : factors) {
                ans *= (cnt + 1);
            }
            cout << ans << endl;
        }
    }
    
    return 0;
}

写在最后

📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取~

在这里插入图片描述

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值