青训营试题算法解析二十

239 阅读6分钟

介绍

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

课程内容和方向

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

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

试题1:最大优美排列

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

def solution(n: int) -> list:
    # 生成从 n 到 1 的降序排列
    result = [i for i in range(n, 0, -1)]
    
    # 验证排列是否满足条件
    for i in range(n):
        if result[result[i] - 1] != n - result[i] + 1:
            return []
    
    return result

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

试题2:最大优美排列

问题描述: 给定两个长度为 n 的数组 a 和 b,定义 f(c) 为数组 c 的所有元素的总和。现在,你需要恰好删除数组 a 或者数组 b 中的一个元素,使得 f(a) 和 f(b) 的异或结果最大。请输出这个最大的异或和。

public class Main {
    public static int solution(int n, int[] a, int[] b) {
        // 计算数组 a 和 b 的总和
        int sumA = 0;
        int sumB = 0;
 
        for (int num : a) {
            sumA += num;
        }
 
        for (int num : b) {
            sumB += num;
        }
 
        int maxXor = 0;
 
        // 尝试删除数组 a 中的每一个元素
        for (int i = 0; i < n; i++) {
            int newSumA = sumA - a[i];
            int newSumB = sumB;
            maxXor = Math.max(maxXor, newSumA ^ newSumB);
        }
 
        // 尝试删除数组 b 中的每一个元素
        for (int i = 0; i < n; i++) {
            int newSumA = sumA;
            int newSumB = sumB - b[i];
            maxXor = Math.max(maxXor, newSumA ^ newSumB);
        }
 
        return maxXor;
    }
 
    public static void main(String[] args) {
        System.out.println(solution(3, new int[]{1, 2, 3}, new int[]{3, 2, 1}) == 5);
        System.out.println(solution(4, new int[]{4, 5, 6, 7}, new int[]{7, 8, 9, 10}) == 51);
        System.out.println(solution(5, new int[]{10, 20, 30, 40, 50}, new int[]{50, 40, 30, 20, 10}) == 248);
    }
}

试题3:最小周长巧克力板组合

问题描述: 小U准备了一些边长为整数的正方形巧克力板,希望选出若干块巧克力板,使它们的总面积恰好等于给定的整数n。巧克力板的周长应尽可能小。巧克力板的总面积恰好为n,而总周长为这些正方形边长的四倍和。请你帮助小U找到一个最优方案,输出最短的周长总和。

def solution(n: int) -> int:
    # 初始化dp数组,dp[i]表示面积为i时的最小周长总和
    dp = [float('inf')] * (n + 1)
    dp[0] = 0  # 面积为0时,周长为0
    
    # 遍历每个面积
    for i in range(1, n + 1):
        # 尝试使用边长为j的正方形
        j = 1
        while j * j <= i:
            # 更新dp[i]
            dp[i] = min(dp[i], dp[i - j * j] + 4 * j)
            j += 1
    
    return dp[n]

if __name__ == '__main__':
    print(solution(n=11) == 20)
    print(solution(n=13) == 20)
    print(solution(n=25) == 20)

试题4:最小覆盖圆面积问题

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

import math

def solution(x1: int, y1: int, x2: int, y2: int, xP: int, yP: int) -> str:
    # 计算矩形的四个顶点坐标
    vertices = [
        (x1, y1),  # 左下角
        (x1, y2),  # 左上角
        (x2, y1),  # 右下角
        (x2, y2)   # 右上角
    ]
    
    # 计算点P到每个顶点的距离
    max_distance = 0
    for x, y in vertices:
        distance = math.sqrt((x - xP) ** 2 + (y - yP) ** 2)
        if distance > max_distance:
            max_distance = distance
    
    # 计算圆的面积
    area = math.pi * max_distance ** 2
    
    # 将面积保留两位小数并转换为字符串
    return f"{area:.2f}"

if __name__ == '__main__':
    print(solution(x1 = 0, y1 = 0, x2 = 1, y2 = 1, xP = 0, yP = 0) == '6.28')
    print(solution(x1 = -2, y1 = -2, x2 = 2, y2 = 2, xP = 0, yP = 0) == '25.13')
    print(solution(x1 = -3, y1 = -1, x2 = 1, y2 = 2, xP = 0, yP = 0) == '40.84')

试题5:最长递减路径节点数查找

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

def solution(R: int, C: int, grid: list) -> int:
    # 定义方向数组,分别表示上、下、左、右四个方向
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    
    # 初始化记忆化数组,memo[i][j] 表示从 (i, j) 开始的最长递减路径长度
    memo = [[0] * C for _ in range(R)]
    
    def dfs(x, y):
        # 如果已经计算过,直接返回
        if memo[x][y] != 0:
            return memo[x][y]
        
        # 初始化当前节点的最长路径长度为1
        memo[x][y] = 1
        
        # 遍历四个方向
        for dx, dy in directions:
            nx, ny = x + dx, y + dy
            # 检查新位置是否在网格内且值严格递减
            if 0 <= nx < R and 0 <= ny < C and grid[nx][ny] < grid[x][y]:
                # 递归计算并更新当前节点的最长路径长度
                memo[x][y] = max(memo[x][y], dfs(nx, ny) + 1)
        
        return memo[x][y]
    
    # 初始化最长路径长度
    max_length = 0
    
    # 遍历每个节点,计算从该节点开始的最长递减路径长度
    for i in range(R):
        for j in range(C):
            max_length = max(max_length, dfs(i, j))
    
    return max_length

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

试题6:矩形棋盘路径问题

问题描述: 小R正在玩一个迷宫游戏。他的起始位置位于一个n行m列的矩形棋盘的左上角 (1,1),目标是移动到棋盘的右下角 (n,m)。棋盘上的每个格子要么是道路("0"),要么是障碍("1")。小R每次只能向右或向下移动,而且必须避开障碍。请你计算小R从 (1,1) 移动到 (n,m) 的所有可能路径数,并将结果对 10^9 + 7 取模。

def solution(n: int, m: int, maze: list) -> int:
    MOD = 10**9 + 7
    # 初始化dp数组,大小为(n, m),所有元素初始化为0
    dp = [[0] * m for _ in range(n)]
    
    # 起点到起点的路径数为1
    dp[0][0] = 1 if maze[0][0] == '0' else 0
    
    # 遍历每个格子
    for i in range(n):
        for j in range(m):
            if maze[i][j] == '0':
                # 如果当前格子是道路,更新路径数
                if i > 0:
                    dp[i][j] += dp[i-1][j]  # 从上方格子过来
                if j > 0:
                    dp[i][j] += dp[i][j-1]  # 从左方格子过来
                dp[i][j] %= MOD  # 取模
    
    # 返回从起点到终点的路径数
    return dp[n-1][m-1]

if __name__ == '__main__':
    print(solution(n=2, m=3, maze=["000", "100"]) == 2)
    print(solution(n=5, m=5, maze=["00000", "10000", "10000", "00000", "00000"]) == 35)
    print(solution(n=3, m=3, maze=["010", "010", "000"]) == 1)