青训营试题算法解析一

192 阅读9分钟

引言

随着AI领域的发展,底层算法确实起到了决定性的作用。为了跟上这个快速发展的领域,我们需要不断学习和提升自己的技能。刷题是一种很好的方式,可以帮助我们巩固基础知识,提高解决问题的能力。

介绍

‌豆包青训营‌是由字节跳动和稀土掘金社区共同发起的技术培训和人才选拔项目。该项目的目标是培养具有职业竞争力的优秀开发工程师,并提供全程免费的课程,不收取任何费用‌。

课程内容和方向

豆包青训营的课程涵盖前端、后端和AI方向。在这个飞速发展的AI时代,学员将与豆包MarsCode团队一起深入探索技术领域,学习和运用AI,提高编程效率‌。此外,课程还包括大数据方向,适合对大数据感兴趣的学员学习‌,

本文提供训练营试题解析供参考

试题1:字符串的加密解密

问题描述: 小C定义了一种加密方式:对于给定的原始字符串 S,将其中每个字母替换为其三重后继,即字母表中该字母的后三个字母。字母 'a' 的三重后继是 'd',字母 'z' 的三重后继是 'c'。现在给定一个加密后的字符串 S',需要通过解密得出原始的字符串 S。

例如,对于加密后的字符串 "def",其原始字符串应该是 "abc"。

def solution(n: int, s: str) -> str:
    # 创建一个空字符串来存储解密后的结果
    decrypted_str = ""
    
    # 遍历输入字符串中的每一个字符
    for char in s:
        # 将字符转换为ASCII码
        ascii_value = ord(char)
        
        # 计算解密后的字符的ASCII码
        # 注意:如果当前字符是 'a' 到 'c',需要特殊处理
        if 'a' <= char <= 'c':
            # 计算解密后的字符
            # 例如:'a' -> 'x', 'b' -> 'y', 'c' -> 'z'
            # 这里需要使用模运算来处理字母表的循环
            new_ascii_value = ord('a') + (ascii_value - ord('a') + 26 - 3) % 26
        else:
            # 对于其他字符,直接减去3
            new_ascii_value = ascii_value - 3
        
        # 将新的ASCII码转换回字符,并添加到解密后的字符串中
        decrypted_str += chr(new_ascii_value)
    
    return decrypted_str

if __name__ == '__main__':
    print(solution(n = 3, s = "def") == 'abc')
    print(solution(n = 5, s = "xyzab") == 'uvwxy')
    print(solution(n = 4, s = "hijk") == 'efgh')

试题2:寻找满足条件的整数

问题描述: 小U 有四个正整数 A、B、C 和 D。你需要找到一个正整数 X(X > 0),使得 A = B * X 且 C = D * X。如果不存在这样的 X,则返回 -1。

def solution(A: int, B: int, C: int, D: int) -> int:
    # 检查是否存在这样的 X
    if A % B != 0 or C % D != 0:
        return -1
    
    # 计算 X1 和 X2
    X1 = A // B
    X2 = C // D
    
    # 检查 X1 和 X2 是否相等
    if X1 == X2:
        return X1
    else:
        return -1

if __name__ == '__main__':
    print(solution(A = 4, B = 2, C = 6, D = 3) == 2)
    print(solution(A = 8, B = 4, C = 15, D = 5) == -1)
    print(solution(A = 9, B = 3, C = 12, D = 4) == 3)

试题3:小C的整数操作挑战

问题描述: 小C手中有一个正整数 n,她每次可以删除这个整数中的一位数字。小C想知道,自己最少需要操作多少次才能使得这个整数成为 5 的倍数。

def solution(n: int) -> int:
    # 将整数 n 转换为字符串
    str_n = str(n)
    
    # 初始化最小删除次数为一个很大的数
    min_deletions = float('inf')
    
    # 遍历字符串的每一位
    for i in range(len(str_n)):
        # 如果当前位是 '0' 或 '5'
        if str_n[i] == '0' or str_n[i] == '5':
            # 计算从当前位到字符串末尾的删除次数
            deletions = len(str_n) - i - 1
            # 更新最小删除次数
            min_deletions = min(min_deletions, deletions)
    
    # 如果没有找到 '0' 或 '5',返回字符串长度(即删除所有位)
    if min_deletions == float('inf'):
        return len(str_n)
    
    return min_deletions

if __name__ == '__main__':
    print(solution(52) == 1)
    print(solution(132) == 3)
    print(solution(1234) == 4)

试题4:小K的找不同挑战

问题描述: 小R最近迷上了这个小游戏。这个游戏中,每一轮都会给出两张非常相似的照片,任务是指出它们之间所有的不同之处。

有一天,小R玩游戏时经过小S身边,瞄到她正盯着一些数字发呆。小R随手指了一个数字,并说这个数字只出现了一次。小S经过仔细验证,发现小R是对的。

为了进一步测试小R的能力,小S设计了一份问卷,包含若干道题目,每道题目有一些数字,要求小R快速回答:在每道题中,最小的一个只出现一次的数字是什么?

由于题目很多,小S无法手动核对所有答案,她希望你能够帮忙实现这个功能。

如果每个数字都出现了多于1次,那么返回-1。

def solution(n: int, nums: list) -> int:
    # 创建一个字典来记录每个数字出现的次数
    count_dict = {}
    
    # 遍历数组,统计每个数字的出现次数
    for num in nums:
        if num in count_dict:
            count_dict[num] += 1
        else:
            count_dict[num] = 1
    
    # 初始化最小只出现一次的数字为无穷大
    min_single_occurrence = float('inf')
    
    # 遍历字典,找到只出现一次的最小数字
    for num, count in count_dict.items():
        if count == 1 and num < min_single_occurrence:
            min_single_occurrence = num
    
    # 如果没有找到符合条件的数字,返回 -1
    if min_single_occurrence == float('inf'):
        return -1
    
    return min_single_occurrence

if __name__ == '__main__':
    print(solution(n = 3, nums = [6, 6, 6]) == -1)
    print(solution(n = 3, nums = [6, 9, 6]) == 9)
    print(solution(n = 5, nums = [1, 2, 2, 3, 3]) == 1)

试题5:小M的最长回文子串挑战

问题描述: 小M发现了一个神奇的现象,她手中有一个字符串 s,她想知道这个字符串中最长的回文子串的长度是多少。你的任务是帮助小M找到该字符串的最长回文子串,并返回它的长度。

回文子串是指从左到右和从右到左字符顺序相同的字符串。

def solution(s: str) -> int:
    def expand_around_center(left: int, right: int) -> int:
        # 从中心向两边扩展,检查是否形成回文
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return right - left - 1

    if not s:
        return 0

    max_length = 0
    for i in range(len(s)):
        # 检查奇数长度的回文
        len1 = expand_around_center(i, i)
        # 检查偶数长度的回文
        len2 = expand_around_center(i, i + 1)
        # 更新最长回文子串的长度
        max_length = max(max_length, len1, len2)

    return max_length

if __name__ == '__main__':
    print(solution("abcbadb") == 5)
    print(solution("ababacab") == 5)
    print(solution("racecarwk") == 7)

试题6:小R的数组最小化问题

问题描述: 小R拿到一个长度为 n 的数组 a,并且每次操作她可以选择数组中的任意一个数将其减少 x。她最多可以进行 k 次操作。小R希望经过 k 次操作之后,数组中的最大值尽可能小。你的任务是帮助她找到经过操作后数组的最大值。

你需要返回经过最多 k 次操作后数组的最大值。

def solution(a: list, k: int, x: int) -> int:
    # 对数组进行排序
    a.sort()
    
    # 使用一个循环来模拟每次操作
    for _ in range(k):
        # 每次操作优先减少当前数组中的最大值
        a[-1] -= x
        
        # 重新排序数组,确保最大值在最后
        a.sort()
    
    # 返回操作后的数组最大值
    return a[-1]

if __name__ == '__main__':
    print(solution(a = [7, 2, 1], k = 3, x = 2) == 2)
    print(solution(a = [10, 5, 8], k = 5, x = 3) == 4)
    print(solution(a = [9, 4, 7], k = 4, x = 1) == 6)

试题7:小U生活事件快乐值最大化

问题描述: 在这里插入图片描述

def solution(n: int, T: int, H: int, t: list, h: list, a: list) -> int:
    # 初始化一个 (T+1) x (H+1) 的二维数组 dp,所有元素初始化为 0
    dp = [[0] * (H + 1) for _ in range(T + 1)]
    
    # 遍历每个事件
    for i in range(n):
        # 对于每个事件,从 T 到 t[i] 和 H 到 h[i] 进行逆序遍历
        for j in range(T, t[i] - 1, -1):
            for k in range(H, h[i] - 1, -1):
                # 更新 dp[j][k] 的值
                dp[j][k] = max(dp[j][k], dp[j - t[i]][k - h[i]] + a[i])
    
    # 返回在时间和精力限制下的最大快乐值
    return dp[T][H]

if __name__ == '__main__':
    print(solution(n = 2, T = 2, H = 2, t = [1, 3], h = [3, 1], a = [3, 4]) == 0)
    print(solution(n = 3, T = 5, H = 5, t = [2, 1, 3], h = [1, 3, 2], a = [10, 7, 8]) == 18)
    print(solution(n = 1, T = 3, H = 3, t = [4], h = [4], a = [5]) == 0)

试题8:小U的完美数挑战

问题描述: 小U定义了一个特别的数,称之为“完美数”,当且仅当这个数中只有一个非零的数字。例如 5000, 4, 1, 10, 200 都是完美数。

现在,小U手中有一个大小为 n 的数组。她希望从中选择两个元素,使得它们的乘积是一个完美数。小U想知道,共有多少种不同的选择可以满足这一条件?

def solution(arr: list) -> int:
    # 定义一个函数来判断一个数是否是完美数
    def is_perfect_number(num: int) -> bool:
        # 将数字转换为字符串
        str_num = str(num)
        # 计算非零字符的数量
        non_zero_count = sum(1 for char in str_num if char != '0')
        # 如果只有一个非零字符,则是完美数
        return non_zero_count == 1

    # 初始化计数器
    count = 0

    # 遍历数组中的所有元素对
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            # 计算两个元素的乘积
            product = arr[i] * arr[j]
            # 检查乘积是否是完美数
            if is_perfect_number(product):
                # 如果是完美数,增加计数器
                count += 1

    # 返回满足条件的元素对的数量
    return count

if __name__ == '__main__':
    print(solution([25, 2, 1, 16]) == 3)
    print(solution([5, 50, 500, 5000]) == 0)
    print(solution([2, 10, 100, 1000]) == 6)

试题9:小U走公路

问题描述: 在这里插入图片描述

def solution(n: int, a: list, x: int, y: int) -> int:
    # 将站点编号调整为从0开始,方便计算
    x -= 1
    y -= 1
    
    # 计算顺时针距离
    clockwise_distance = 0
    if x <= y:
        # 从x到y的顺时针距离
        for i in range(x, y):
            clockwise_distance += a[i]
    else:
        # 从x到n,再从1到y的顺时针距离
        for i in range(x, n):
            clockwise_distance += a[i]
        for i in range(0, y):
            clockwise_distance += a[i]
    
    # 计算逆时针距离
    counterclockwise_distance = 0
    if x >= y:
        # 从y到x的逆时针距离
        for i in range(y, x):
            counterclockwise_distance += a[i]
    else:
        # 从y到n,再从1到x的逆时针距离
        for i in range(y, n):
            counterclockwise_distance += a[i]
        for i in range(0, x):
            counterclockwise_distance += a[i]
    
    # 返回最短距离
    return min(clockwise_distance, counterclockwise_distance)

if __name__ == '__main__':
    print(solution(3, [1, 2, 2], 2, 3) == 2)
    print(solution(3, [1, 2, 2], 1, 3) == 2)
    print(solution(4, [3, 5, 7, 2], 1, 4) == 2)