【拼多多笔试题汇总】2024-05-09-拼多多春招笔试题-三语言题解(Cpp/Java/Python)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员

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

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

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

📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 清隆领取,会在飞书进行同步的跟新。

☀️ 01.汉堡王优惠活动

问题描述

K小姐最喜欢到多哆村的金哆炸鸡店吃汉堡,每个汉堡原价 10 10 10 元。为了回馈老顾客,炸鸡店开展了拼团活动:每找到一个朋友一起购买,就可以减少 1 1 1 元,但价格最低只能降到 5 5 5 元(否则就要亏本啦)。

现在 K小姐 手上有 N N N 元钱,同时有 M M M 个朋友也想吃汉堡。K小姐 想知道自己最多能买多少个汉堡,以及在买最多汉堡的情况下最少要花多少钱。

输入格式

第一行包含一个正整数 T T T,表示测试用例的数量。

接下来 T T T 行,每行包含两个正整数 N N N M M M,分别表示 K小姐 的钱数以及一起购买汉堡的朋友数量。

输出格式

对于每组测试用例,输出一行,包含两个整数,分别表示 K小姐 能购买的最多汉堡数量,以及购买最多汉堡时最少需要花的钱数。

样例输入

3
100 0
20 18
5 3

样例输出

10 100
3 16
0 0

数据范围

  • 1 ≤ T ≤ 100 1 \leq T \leq 100 1T100
  • 1 ≤ N ≤ 100050 1 \leq N \leq 100050 1N100050
  • 0 ≤ M ≤ 1000 0 \leq M \leq 1000 0M1000

题解

本题的关键是判断能够凑成多少个优惠价 5 5 5 元的汉堡。

首先,我们可以计算出朋友数量可以凑成的 5 5 5 元汉堡个数 t t t,以及凑成这些汉堡后剩余的朋友数量 m m m

如果 t t t 5 5 5 元汉堡的总价格超过了 K小姐 的钱数 N N N,那么最多只能买 ⌊ N 5 ⌋ \lfloor \frac{N}{5} \rfloor 5N 个汉堡,花费 5 × ⌊ N 5 ⌋ 5 \times \lfloor \frac{N}{5} \rfloor 5×5N 元。

否则,在买完 t t t 5 5 5 元汉堡后,如果剩下的钱加上剩余的朋友数量可以再凑成一个 10 − m 10-m 10m 元的汉堡,那么就再买一个,并将剩下的钱按照 10 10 10 元一个汉堡的价格继续购买。如果不能凑成 10 − m 10-m 10m 元的汉堡,那么最多就只能买 t t t 个汉堡,花费 5 × t 5 \times t 5×t 元。

参考代码

  • Python
T = int(input())

def solve():
    n, m = map(int, input().split())
    t = m // 5  # 5元汉堡个数
    m %= 5
    
    if t * 5 > n:
        print(n // 5, (n // 5) * 5)
    else:
        n -= t * 5
        if n >= 10 - m:
            n -= (10 - m)
            print(t + 1 + (n // 10), t * 5 + 10 - m + (n // 10) * 10)
        else:
            print(t, t * 5)

for _ in range(T):
    solve()
  • Java
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) {
            solve(sc);
        }
    }
    
    private static void solve(Scanner sc) {
        int n = sc.nextInt();
        int m = sc.nextInt();
        int t = m / 5;  // 5元汉堡个数
        m %= 5;
        
        if (t * 5 > n) {
            System.out.println((n / 5) + " " + ((n / 5) * 5));
        } else {
            n -= t * 5;
            if (n >= 10 - m) {
                n -= (10 - m);
                System.out.println((t + 1 + (n / 10)) + " " + (t * 5 + 10 - m + (n / 10) * 10));
            } else {
                System.out.println(t + " " + (t * 5));
            }
        }
    }
}
  • Cpp
#include <iostream>

using namespace std;

void solve() {
    int n, m;
    cin >> n >> m;
    int t = m / 5;  // 5元汉堡个数
    m %= 5;
    
    if (t * 5 > n) {
        cout << n / 5 << " " << (n / 5) * 5 << endl;
    } else {
        n -= t * 5;
        if (n >= 10 - m) {
            n -= (10 - m);
            cout << t + 1 + (n / 10) << " " << t * 5 + 10 - m + (n / 10) * 10 << endl;
        } else {
            cout << t << " " << t * 5 << endl;
        }
    }
}

int main() {
    int T;
    cin >> T;
    
    while (T--) {
        solve();
    }
    
    return 0;
}

🌤 02.二进制字符串的十进制值

题目描述

K小姐特别喜欢二进制字符串。有一天,博学的 A 先生在迁居时遇到了 K 小姐,他准备考考她。

A先生每次会给K小姐一个长度为 n n n 的二进制字符串 s s s。他定义了一种新的子串 d i d_i di,作为十进制表示形式为 s [ i : i − 1 ] s[i:i-1] s[i:i1] 的数字(可能有前导零)。A 先生定义字符串的十进制值 f ( s ) f(s) f(s) 为所有有效的 d i d_i di 的总和,换句话说:

f ( s ) = ∑ i = 1 n − 1 d i f(s) = \sum_{i=1}^{n-1} d_i f(s)=i=1n1di

例如,对于字符串 s = 1101 s=1101 s=1101

  • d 1 = s [ 0 : 1 ] = 11 d_1 = s[0:1] = 11 d1=s[0:1]=11
  • d 2 = s [ 1 : 2 ] = 10 d_2 = s[1:2] = 10 d2=s[1:2]=10
  • d 3 = s [ 2 : 3 ] = 01 d_3 = s[2:3] = 01 d3=s[2:3]=01

因此, f ( s ) = 11 + 10 + 1 = 22 f(s) = 11 + 10 + 1 = 22 f(s)=11+10+1=22

A 先生允许 K 小姐每次可以交换字符串的任意两个相邻元素,最多可以进行 k k k 次操作。他问 K 小姐,在进行操作后,字符串的十进制值最小是多少。K 小姐喜欢分享,于是她邀请你一起解决这个问题。

输入格式

第一行包含一个整数 t t t,表示测试用例的数量。 ( 1 ≤ t ≤ 100 ) (1 \le t \le 100) (1t100)

对于每组测试用例:

  • 第一行包含两个整数 n n n k k k,分别表示字符串的长度和允许的最大操作数。 ( 2 ≤ n ≤ 1 0 5 , 0 ≤ k < 1 0 5 ) (2 \le n \le 10^5, 0 \le k < 10^5) (2n105,0k<105)
  • 第二行包含一个长度为 n n n,仅由 0 0 0 1 1 1 组成的二进制字符串 s s s

输出格式

对于每组测试用例,分别输出一行,每行一个整数,表示在最多可以进行 k k k 次操作后字符串的最小十进制值。

样例输入

2
5 0
10100
7 2
0010100

样例输出

21
12

数据范围

  • 1 ≤ t ≤ 100 1 \le t \le 100 1t100
  • 2 ≤ n ≤ 1 0 5 2 \le n \le 10^5 2n105
  • 0 ≤ k < 1 0 5 0 \le k < 10^5 0k<105

题解

观察可以发现中间部分的 ‘1’ 对答案的贡献不变,只有首尾的 ‘1’ 贡献会不一样,主要策略是尽量将 ‘1’ 移动到字符串的尾部,从而减少由 ‘1’ 产生的高权重。首先尝试将最后一个 ‘1’ 尽可能右移,如果剩余操作数还允许,再将第一个 ‘1’ 尽可能左移。这样可以最大程度减少 ‘1’ 的有效出现次数,从而降低总和。

参考代码

  • Python
def solve():
    n, k = map(int, input().split())
    s = input().strip()
    idx0 = s.find('1')
    idx1 = s.rfind('1')

    # Function to perform operation 0
    def op0(idx0):
        nonlocal k
        if idx0 == -1:
            return
        while k > 0 and idx0 > 0:
            s_lst = list(s)
            s_lst[idx0], s_lst[idx0 - 1] = s_lst[idx0 - 1], s_lst[idx0]
            s = ''.join(s_lst)
            k -= 1
            idx0 -= 1

    # Function to perform operation 1
    def op1(idx1):
        nonlocal k
        if idx1 == -1:
            return
        while k > 0 and idx1 < n - 1:
            s_lst = list(s)
            s_lst[idx1], s_lst[idx1 + 1] = s_lst[idx1 + 1], s_lst[idx1]
            s = ''.join(s_lst)
            k -= 1
            idx1 += 1

    if n - idx1 - 1 <= k:
        op1(idx1)
    op0(idx0)
    res = 0
    for i in range(n - 1):
        res += int(s[i:i + 2])
    print(res)

T = int(input())
for _ in range(T):
    solve()

  • Java
import java.util.Scanner;

public class Main {

    static void solve() {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        String s = scanner.next();
        int idx0 = s.indexOf('1');
        int idx1 = s.lastIndexOf('1');

        // 操作0:将'1'向左移动
        Runnable op0 = () -> {
            if (idx0 == -1) return;
            while (k > 0 && idx0 > 0) {
                char temp = s.charAt(idx0);
                s.setCharAt(idx0, s.charAt(idx0 - 1));
                s.setCharAt(idx0 - 1, temp);
                k--;
                idx0--;
            }
        };

        // 操作1:将'1'向右移动
        Runnable op1 = () -> {
            if (idx1 == -1) return;
            while (k > 0 && idx1 < n - 1) {
                char temp = s.charAt(idx1);
                s.setCharAt(idx1, s.charAt(idx1 + 1));
                s.setCharAt(idx1 + 1, temp);
                k--;
                idx1++;
            }
        };

        if (n - idx1 - 1 <= k)
            op1.run();
        op0.run();
        int res = 0;
        for (int i = 0; i < n - 1; i++)
            res += Integer.parseInt(s.substring(i, i + 2));
        System.out.println(res);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        while (T-- > 0)
            solve();
    }
}

  • Cpp
#include <bits/stdc++.h>

using namespace std;

void solve() {
    int n, k;
    cin >> n >> k;
    string s;
    cin >> s;
    int idx0 = s.find('1');
    int idx1 = s.rfind('1');

    // Function to perform operation 0
    auto op0 = [&](int &idx0) {
        if (idx0 == -1) return;
        while (k && idx0) {
            swap(s[idx0], s[idx0 - 1]);
            k--;
            idx0--;
        }
    };

    // Function to perform operation 1
    auto op1 = [&](int &idx1) {
        if (idx1 == -1) return;
        while (k && idx1 < n - 1) {
            swap(s[idx1], s[idx1 + 1]);
            idx1++;
            k--;
        }
    };

    if (n - idx1 - 1 <= k)
        op1(idx1);
    op0(idx0);
    int res = 0;
    for (int i = 0; i < n - 1; i++)
        res += stoi(s.substr(i, 2));
    cout << res << "\n";
}

int main() {
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

⛅️ 03.字符串消消乐

问题描述

LYA 最近沉迷于一款字符串消除游戏。游戏开始时,LYA 会得到一个长度为 N N N 的仅由大小写字母构成的字符串 S S S

游戏中,LYA 可以重复执行以下操作:从 S S S 中删除最长且最靠左的连续相同字符构成的子串。

LYA 想知道,最少经过多少次操作后,能够将整个字符串 S S S 删除完全。

输入格式

第一行包含一个整数 N N N,表示字符串的长度 ( 1 ≤ N ≤ 100 , 000 ) (1 \leq N \leq 100,000) (1N100,000)

第二行包含一个字符串 S S S,表示游戏初始时的字符串。

输出格式

输出一个整数,表示将字符串完全删除所需的最少操作次数。

样例输入

4
aBBa

样例输出

2

样例解释

第一次操作,消除 BB,剩下的字符串为 aa
第二次操作,消除 aa

数据范围

1 ≤ N ≤ 100 , 000 1 \leq N \leq 100,000 1N100,000

题解

可以每次找到最长且最靠左的连续相同字符构成的子串,将其删除。重复这一过程,直到字符串为空。

具体实现时,可以维护一个集合,存储当前所有连续相同字符构成的子串的信息(子串长度、左右端点位置)。每次从集合中取出长度最大的子串删除,并更新相邻子串的信息。重复此过程,直到集合为空。

时间复杂度为 O ( N log ⁡ N ) O(N \log N) O(NlogN),其中 N N N 为字符串长度。空间复杂度为 O ( N ) O(N) O(N)

tips: 据说直接暴力replace也能过哦

参考代码

  • Cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n;
    cin >> n;
    string s;
    cin >> s;
    
    char last = s[0];
    int cnt = 1, left = 0;
    map<int, array<int, 3>> mpl, mpr;
    set<array<int, 3>> se;
    
    for (int i = 1; i < n; i++) {
        if (s[i] != last) {
            se.insert({-cnt, left, i - 1});
            mpl[left] = {i - 1, last, cnt};
            mpr[i - 1] = {left, last, cnt};
            left = i;
            cnt = 1;
            last = s[i];
        } else {
            cnt++;
        }
    }
    
    se.insert({-cnt, left, n - 1});
    mpl[left] = {n - 1, last, cnt};
    mpr[n - 1] = {left, last, cnt};
    
    int res = 0;
    while (!se.empty()) {
        auto fi = *se.begin();
        auto [cnt, l, r] = fi;
        char lc = mpr[l - 1][1];
        char rc = mpl[r + 1][1];
        if (lc == rc) {
            int lidx = mpr[l - 1][0];
            int ridx = mpl[r + 1][0];
            int lcnt = mpr[l - 1][2];
            int rcnt = mpl[r + 1][2];
            se.erase({-lcnt, lidx, l - 1});
            se.erase({-rcnt, r + 1, ridx});
            se.insert({-(lcnt + rcnt), lidx, ridx});
            mpl.erase(r + 1);
            mpr.erase(l - 1);
            mpl[lidx] = {ridx, lc};
            mpr[ridx] = {lidx, lc};
        }
        se.erase(fi);
        mpr.erase(l);
        mpl.erase(r);
        if (se.empty()) break;
        res++;
    }
    
    cout << res << "\n";
    return 0;
}

☁️ 04.魔法秘境

题目描述

LYA 在探索一片神秘的魔法领地时,发现了一个蕴含着强大魔法能量的秘境。这个秘境被划分为 n n n 个独特且连续的区域,其中第 i i i 个区域的魔法能量值为 x i x_i xi

为了最大化修炼效果,LYA 计划施展一个强大的结界覆盖一系列连续的区域。然而,施展结界需要消耗巨大的魔力,只有当连续被覆盖的区域数量至少达到 m m m 个时,施展结界才是划算的。

请你帮 LYA 计算出在结界覆盖的范围内,每个区域的魔法能量的平均值最大可以达到多少。结果四舍五入保留三位小数。

输入格式

第一行包含一个整数 T T T,表示测试用例的数量( 1 ≤ T ≤ 10 1 \leq T \leq 10 1T10)。

对于每组测试用例:
第一行为两个整数 n n n m m m,分别表示魔法区域的个数和结界至少需要笼罩的连续区域个数( 1 ≤ m ≤ n ≤ 1 0 5 1 \leq m \leq n \leq 10^5 1mn105)。
接下来的 n n n 行,每行一个整数 x i x_i xi,表示第 i i i 个区域的魔法能量值( 1 ≤ x i ≤ 5000 1 \leq x_i \leq 5000 1xi5000)。

输出格式

对于每组测试用例,输出一行,为结界覆盖范围内魔法能量的最大平均值,结果四舍五入保留三位小数。

样例输入

1
8 3
4
5
6
7
9
9
6
8

样例输出

8.333

数据范围

  • 1 ≤ T ≤ 10 1 \leq T \leq 10 1T10
  • 1 ≤ m ≤ n ≤ 1 0 5 1 \leq m \leq n \leq 10^5 1mn105
  • 1 ≤ x i ≤ 5000 1 \leq x_i \leq 5000 1xi5000

题解

本题可以使用二分答案的思路来解决。可以二分枚举平均值,判断是否存在一个长度至少为 m m m 的区间,使得区间内的平均值大于等于当前二分的值。

具体地,我们可以先求出数组的前缀和,然后枚举区间右端点,利用前缀和数组快速计算出区间和。如果区间长度大于等于 m m m,且区间和大于等于二分的值与区间长度的乘积,则说明当前二分的值是可行的,可以缩小右区间,否则需要缩小左区间。

最后二分的结果就是最大的平均值。

参考代码

  • Python
T = int(input())
for _ in range(T):
    n, m = map(int, input().split())
    arr = [int(input()) for _ in range(n)]
    
    def check(avg):
        minv = 0
        sum = [0] * (n + 1)
        for i in range(1, n + 1):
            sum[i] = sum[i - 1] + arr[i - 1] - avg
        for i in range(m, n + 1):
            minv = min(minv, sum[i - m])
            if sum[i] >= minv:
                return True
        return False
    
    l, r = 0, max(arr)
    while r - l > 1e-5:
        mid = (l + r) / 2
        if check(mid):
            l = mid
        else:
            r = mid
    print(f"{r:.3f}")
  • Java
import java.util.*;

public class Main {
    static final int MAXN = 100005;
    static int[] arr = new int[MAXN];
    static double[] sum = new double[MAXN];
    static int n, m;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        while (T-- > 0) {
            n = sc.nextInt();
            m = sc.nextInt();
            double l = 0, r = 0;
            for (int i = 1; i <= n; ++i) {
                arr[i] = sc.nextInt();
                r = Math.max(r, (double) arr[i]);
            }

            while (r - l > 1e-5) {
                double mid = (l + r) / 2;
                if (check(mid)) {
                    l = mid;
                } else {
                    r = mid;
                }
            }

            System.out.printf("%.3f\n", r);
        }
    }

    static boolean check(double avg) {
        for (int i = 1; i <= n; ++i) {
            sum[i] = sum[i - 1] + arr[i] - avg;
        }
        double minv = 0;
        for (int i = m; i <= n; ++i) {
            minv = Math.min(minv, sum[i - m]);
            if (sum[i] >= minv) {
                return true;
            }
        }
        return false;
    }
}
  • Cpp
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 100005;
int arr[MAXN];
double sum[MAXN];
int n, m;

bool check(double avg) {
    for (int i = 1; i <= n; ++i) {
        sum[i] = sum[i - 1] + arr[i] - avg;
    }
    double minv = 0;
    for (int i = m; i <= n; ++i) {
        minv = min(minv, sum[i - m]);
        if (sum[i] >= minv) {
            return true;
        }
    }
    return false;
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        double l = 0, r = 0;
        for (int i = 1; i <= n; ++i) {
            cin >> arr[i];
            r = max(r, (double) arr[i]);
        }

        while (r - l > 1e-5) {
            double mid = (l + r) / 2;
            if (check(mid)) {
                l = mid;
            } else {
                r = mid;
            }
        }

        printf("%.3f\n", r);
    }
    return 0;
}

写在最后

📧 清隆这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 清隆领取,会在飞书进行同步的跟新。

在这里插入图片描述
在这里插入图片描述

  • 24
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值