笔试真题解析 | 4.11蚂蚁金服暑期实习三道编程题

恭喜发现宝藏!搜索公众号【TechGuide】回复公司名,解锁更多新鲜好文和互联网大厂的笔经面经。
作者@TechGuide【全网同名】

订阅专栏【进阶版】2023最新大厂笔试真题 & 题解,不容错过的宝藏资源!

第一题:素数统计

题目描述

给一个数组,有多少素数元素的出现次数也是素数。注意:重复元素的次数也计算在内

输入描述

一个整数数组,长度为n(1 <= n <= 10e5),数组中元素的取值范围为[1, 10e6]。

输出描述

一个整数,表示数组中有多少元素是素数,且出现次数也是素数。

样例

输入

[1, 2, 3, 2, 5, 7, 7, 7, 5]

输出

3

样例说明

2出现了2次,5出现了2次,7出现了3次,它们都是素数,因此输出为3。

思路

使用hashmap统计频次,签到题。

代码

Python版本

def countPrimeAndPrimeOccurrence(nums):
    # 统计每个元素的出现次数
    countMap = {}
    for num in nums:
        countMap[num] = countMap.get(num, 0) + 1
    
    # 统计素数和出现次数为素数的元素个数
    primeCount = 0
    for num in countMap:
        if isPrime(num) and isPrime(countMap[num]):
            primeCount += 1
    
    return primeCount
    
# 判断一个数是否是素数
def isPrime(num):
    if num <= 1:
        return False
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            return False
    return True

# 主函数
if __name__ == '__main__':
    nums = [1, 2, 3, 2, 5, 7, 7, 7, 5]
    count = countPrimeAndPrimeOccurrence(nums)
    print(count)
# vx公众号关注TechGuide 实时题库 闪电速递。

Java版本

import java.util.*;

public class Main {
    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 2, 5, 7, 7, 7, 5};
        int count = countPrimeAndPrimeOccurrence(nums);
        System.out.println(count);
    }
    
    public static int countPrimeAndPrimeOccurrence(int[] nums) {
        // 统计每个元素的出现次数
        Map<Integer, Integer> countMap = new HashMap<>();
        for (int num : nums) {
            countMap.put(num, countMap.getOrDefault(num, 0) + 1);
        }
        
        // 统计素数和出现次数为素数的元素个数
        int primeCount = 0;
        for (int num : countMap.keySet()) {
            if (isPrime(num) && isPrime(countMap.get(num))) {
                primeCount++;
            }
        }
        
        return primeCount;
    }
    
    // 判断一个数是否是素数
    public static boolean isPrime(int num) {
        if (num <= 1) {
            return false;
        }
        for (int i = 2; i <= Math.sqrt(num); i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }
}
// vx公众号关注TechGuide 实时题库 闪电速递

CPP版本

#include <iostream>
#include <vector>
#include <unordered_map>
#include <cmath>

using namespace std;

int countPrimeAndPrimeOccurrence(vector<int>& nums) {
    // 统计每个元素的出现次数
    unordered_map<int, int> countMap;
    for (int num : nums) {
        countMap[num] = countMap[num] + 1;
    }
    
    // 统计素数和出现次数为素数的元素个数
    int primeCount = 0;
    for (auto& kv : countMap) {
        if (isPrime(kv.first) && isPrime(kv.second)) {
            primeCount++;
        }
    }
    
    return primeCount;
}

// 判断一个数是否是素数
bool isPrime(int num) {
    if (num <= 1) {
        return false;
    }
    for (int i = 2; i <= sqrt(num); i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}

// 主函数
int main() {
    vector<int> nums = {1, 2, 3, 2, 5, 7, 7, 7, 5};
    int count = countPrimeAndPrimeOccurrence(nums);
    cout << count << endl;
    return 0;
}
// vx公众号关注TechGuide 实时题库 闪电速递

第二题:小球运动

题目描述

给一个n×m的矩阵代表桌子,给定初始坐标(x,y)代表小球位置,给定初始运动方向(左上、左下、右上、右下)。小球每移动一次花费1秒(只能按前面的四个方向移动),碰到桌边会90度反弹,桌角会180度反弹。计算多长时间后,小球回到初始位置。
1≤n,m≤10e9

输入描述

第一行输入四个正整数 n, m, x, y,表示矩阵的行数、列数和小球的初始位置坐标。
第二行输入一个字符串 s,表示小球的初始运动方向。字符串长度为 2,第一个字符表示垂直方向的运动方向(‘U’ 表示向上,‘D’ 表示向下),第二个字符表示水平方向的运动方向(‘L’ 表示向左,‘R’ 表示向右)。

输出描述

输出一个整数,表示小球回到初始位置所需的最少时间。
如果小球永远无法回到初始位置,则输出 -1。

样例

输入

5 7 1 7 
DL

输出

24

思路

模拟。将不同方向统一到DR方向处理,将小球的移动方向统一,再分别处理四种类型的点,求出最短时间。具体实现中使用扩展欧几里得算法求解方程ax+by=c的最小正整数解,之后用min函数不断更新最短时间就行。

代码

Python版本

import sys
from typing import List

def exgcd(a:int, b:int, x:int, y:int) -> int:
    if b == 0:
        x = 1
        y = 0
        return a
    d = exgcd(b, a % b, y, x)
    y = y - a // b * x
    return d

def solve(a:int, b:int, c:int) -> int:
    x, y = 0, 0
    gcd = exgcd(a, b, x, y)
    if c % gcd != 0:
        return -1
    x *= c // gcd
    x %= abs(b // gcd)
    if x <= 0:
        x += abs(b // gcd)
    return x

def main() -> None:
    n, m, start_x, start_y = map(int, input().split())
    s = input().strip()
    if s == 'UR':
        start_x = n - start_x + 1
    elif s == 'UL':
        start_x = n - start_x + 1
        start_y = m - start_y + 1
    elif s == 'DL':
        start_y = m - start_y + 1
    ans = 2e18
    a, b = 2 * (n - 1), -2 * (m - 1)
    c = 0
    p = solve(a, b, c)
    if p != -1:
        ans = min(ans, 2 * p * (n - 1))
    c = -2 * start_y + 2
    p = solve(a, b, c)
    if p != -1:
        ans = min(ans, 2 * p * (n - 1))
    c = 2 * start_x - 2
    p = solve(a, b, c)
    if p != -1:
        ans = min(ans, 2 * p * (n - 1) - 2 * start_x + 2)
    c = 2 * start_x - 2 * start_y
    p = solve(a, b, c)
    if p != -1:
        ans = min(ans, 2 * p * (n - 1) - 2 * start_x + 2)
    print(ans if ans != 2e18 else -1)

if __name__ == '__main__':
    main()
# vx公众号关注TechGuide 实时题库 闪电速递。

Java版本

import java.util.Scanner;

public class Main {
    static int n, m, x, y, start_x, start_y;
    static char[] s = new char[3];

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        start_x = sc.nextInt();
        start_y = sc.nextInt();
        s = sc.next().toCharArray();

        if(s[0] == 'U' && s[1] == 'R') {
            start_x = n - start_x + 1;
        }else if(s[0] == 'U' && s[1] == 'L') {
            start_x = n - start_x + 1;
            start_y = m - start_y + 1;
        }else if(s[0] == 'D' && s[1] == 'L') {
            start_y = m - start_y + 1;
        }

        long ans = Long.MAX_VALUE;
        int a = 2 * (n - 1), b = -2 * (m - 1), c = 0;
        int p = solve(a, b, c);
        if(p != -1) ans = Math.min(ans, 2L * p * (n - 1));

        a = 2 * (n - 1); b = -2 * (m - 1); c = -2 * start_y + 2;
        p = solve(a, b, c);
        if(p != -1) ans = Math.min(ans, 2L * p * (n - 1));

        a = 2 * (n - 1); b = -2 * (m - 1); c = 2 * start_x - 2;
        p = solve(a, b, c);
        if(p != -1) ans = Math.min(ans, 2L * p * (n - 1) - 2L * start_x + 2);

        a = 2 * (n - 1); b = -2 * (m - 1); c = 2 * start_x - 2 * start_y;
        p = solve(a, b, c);
        if(p != -1) ans = Math.min(ans, 2L * p * (n - 1) - 2 * start_x + 2);

        System.out.println(ans == Long.MAX_VALUE ? -1 : ans);
        sc.close();
    }

    //求解方程ax + by = c的最小正整数解
    private static int solve(int a, int b, int c) {
        int x = 0, y = 0;
        int gcd = exgcd(a, b, x, y);
        if(c % gcd != 0) return -1;
        x = x * (c / gcd);
        x = x % (Math.abs(b / gcd));
        if(x <= 0) x = x + Math.abs(b / gcd);
        return x;
    }

    private static int exgcd(int a, int b, int x, int y) {
        if(b == 0) {
            x = 1;
            y = 0;
            return a;
        }
        int d = exgcd(b, a % b, y, x);
        y = y - a / b * x;
        return d;
    }
}
// vx公众号关注TechGuide 实时题库 闪电速递

第三题:字母填写

题目描述

一个01字符串,长度最大为200000。0代表蓝色,1代表红色。在每个格子上填一个小写字母,使得相同字母的颜色是相同的,希望最终出现次数最多的字母的出现次数最小。输出该小写字母组成的字符串(长度与01串相同)。

输入描述

一个01字符串s,长度最大为200000。0代表蓝色,1代表红色。

输出描述

一个小写字母组成的字符串,使得相同字母的颜色是相同的,希望最终出现次数最多的字母的出现次数最小,长度与01串相同。

样例

输入

01010101010101010101010101

输出

anbocpdqerfsgthuivjwkxlymz

思路

如果全0或全1,直接平均分配。否则,思路是根据0和1的数量,对字符串进行分组,然后通过计算不同划分比例得到最少出现次数最多字母的数量,最后根据最佳划分比例分别为0和1的位置填入字母。

代码

Python版本

s = input().strip()
n = len(s)
ind0 = [i for i in range(n) if s[i] == '0']
ind1 = [i for i in range(n) if s[i] == '1']
a, b = len(ind0), len(ind1)
ret = ''
if a == 0 or b == 0:
    cnts = [n//26]*26
    n = n % 26
    for i in range(n):
        cnts[i] += 1
    for i in range(26):
        ret += chr(ord('a')+i) * cnts[i]
else:
    minn = 0x3f3f3f3f
    best_x, best_y = None, None
    for x in range(1, 26):
        y = 26 - x
        cur = max(math.ceil(a / x), math.ceil(b / y))
        if cur < minn:
            best_x, best_y = x, y
            minn = cur
    ret = ['!'] * n
    ich = 0
    for i in ind0:
        ret[i] = chr(ord('a')+ich)
        ich = (ich + 1) % best_x
    ch = chr(ord('a') + best_x)
    ich = 0
    for i in ind1:
        ret[i] = chr(ord(ch)+ich)
        ich = (ich + 1) % best_y
    ret = ''.join(ret)
print(ret)
# vx公众号关注TechGuide 实时题库 闪电速递。

Java版本

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        int n = s.length();
        List<Integer> ind0 = new ArrayList<>(), ind1 = new ArrayList<>();
        for (int i = 0; i < n; ++i) {
            if (s.charAt(i) == '0') ind0.add(i);
            else ind1.add(i);
        }
        int a = ind0.size(), b = ind1.size();
        String ret;
        if (a == 0 || b == 0) {
            int[] cnts = new int[26];
            Arrays.fill(cnts, n / 26);
            n = n % 26;
            for (int i = 0; i < n; ++i) {
                cnts[i]++;
            }
            ret = "";
            for (int i = 0; i < 26; ++i) {
                while (cnts[i]-- > 0) {
                    ret += (char)('a' + i);
                }
            }
        } else {
            int minn = 0x3f3f3f3f, bestX = 0, bestY = 0;
            for (int x = 1; x < 26; ++x) {
                int y = 26 - x;
                int cur = (int)Math.ceil((double)a / x) + (int)Math.ceil((double)b / y);
                if (cur < minn) {
                    bestX = x;
                    bestY = y;
                    minn = cur;
                }
            }
            int ich = 0;
            ret = new String(new char[n]).replace("\0", "!");
            for (int i = 0; i < a; ++i) {
                ret = ret.substring(0, ind0.get(i)) + (char)('a' + ich) + ret.substring(ind0.get(i) + 1);
                ich = (ich + 1) % bestX;
            }
            char ch = (char)('a' + bestX);
            ich = 0;
            for (int i = 0; i < b; ++i) {
                ret = ret.substring(0, ind1.get(i)) + (char)(ch + ich) + ret.substring(ind1.get(i) + 1);
                ich = (ich + 1) % bestY;
            }
        }
        System.out.println(ret);
    }
}
// vx公众号关注TechGuide 实时题库 闪电速递
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechGuide

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值