青训营试题算法解析十五

介绍

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

课程内容和方向

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

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

试题1:股票市场交易策略优化

问题描述: 小R近期表现出色,公司决定以股票的形式给予奖励,并允许他在市场上进行交易以最大化收益。给定一个数组,数组中的第 i 个元素代表第 i 天的股票价格。小R需要设计一个算法来实现最大利润。

股票交易规则如下:

小R可以多次买卖股票,但在买入新的股票前必须卖出之前的股票。 每次卖出股票后存在一天的冷冻期,在冷冻期内小R不能购买股票。 你的任务是帮助小R计算出在遵守交易规则的情况下能够获得的最大利润。

stocks: 一个整数列表,表示连续几天内的股票价格

python 复制代码
def solution(stocks):
    if not stocks:
        return 0
    
    n = len(stocks)
    # 初始化状态数组
    hold = [0] * n
    unhold = [0] * n
    
    # 初始化第一天的状态
    hold[0] = -stocks[0]
    unhold[0] = 0
    
    for i in range(1, n):
        # 更新持有股票的状态
        hold[i] = max(hold[i-1], # 前一天就持有股票
                      (unhold[i-2] if i >= 2 else 0) - stocks[i]) # 前两天不持有股票,今天买入
        
        # 更新不持有股票的状态
        unhold[i] = max(unhold[i-1], # 前一天就不持有股票
                        hold[i-1] + stocks[i]) # 前一天持有股票,今天卖出
    
    # 返回最后一天不持有股票的最大利润
    return unhold[n-1]

if __name__ == "__main__":
    #  You can add more test cases here
    print(solution([1, 2]) == 1 )
    print(solution([2, 1]) == 0 )
    print(solution([1, 2, 3, 0, 2]) == 3 )
    print(solution([2, 3, 4, 5, 6, 7]) == 5 )
    print(solution([1, 6, 2, 7, 13, 2, 8]) == 12 )

试题2:数字魔法的加一操作

问题描述:

java 复制代码
import java.math.BigInteger;
import java.util.LinkedList;

public class Main {
    public static int solution(int n, int k, String numStr) {

        LinkedList<Integer> list = new LinkedList<>();
        for (char word : numStr.toCharArray()) {
            int num = word - '0';
            list.add(num);
        }

        // 使用内置方法反转链表
        java.util.Collections.reverse(list);

        // 逐位加一
        for(int j=0;j<k;j++){
            for (int i = 0; i < list.size(); i++) {
                int value = list.get(i) + 1;
                if (value <= 9) {
                    list.set(i, value);
                } else if (value == 10) {
                    list.set(i, 0);
                    list.add(i + 1, 1);
                    i++;
                }
            }
        }

        // 再次反转回来
        java.util.Collections.reverse(list);
        // 构建 BigInteger 对象
        StringBuilder sb = new StringBuilder();
        for (Integer num : list) {
            sb.append(num);
        }
        BigInteger number = new BigInteger(sb.toString());
        BigInteger text = new BigInteger("1000000007");
//        System.out.println(number.remainder(text).toString());
//        //检查转换后数据的类型
//        System.out.println(number.remainder(text).toString().getClass());
        return number.remainder(text).intValue();
    }

    public static void main(String[] args) {
        int result1 = solution(3, 1, "798");
        System.out.println(result1 == 8109);

        int result2 = solution(4, 1, "8109");
        System.out.println(result2 == 92110);

        int result3 = solution(5, 1, "92110");
        System.out.println(result3 == 103221);
    }
}

试题3:摇骰子的胜利概率

问题描述: 小U和小S正在玩一个有趣的骰子游戏。每个骰子都有固定数量的面数k(2<=k<=8),每一面的点数分别是1到k。小U拥有n个骰子,每个骰子i的面数是 a_i,摇到每一面的概率均为 1/a_i。小S则有m个骰子,每个骰子j的面数是 b_j,摇到每一面的概率均为 1/b_j。

两人分别同时摇各自的骰子,并将摇出的点数相加,得分较高的一方获胜,得分相同则为平局。游戏只进行一次,没有重赛。现在小U想知道他获胜的概率是多少。你能帮他计算吗?

java 复制代码
import java.util.Arrays;

public class Main {
    public static double solution(int n, int m, int[] arrayN, int[] arrayM) {
        double[] probA = calculateProbabilities(arrayN);
        double[] probB = calculateProbabilities(arrayM);

        double winProbability = 0.0;

        for (int i = 0; i < probA.length; i++) {
            for (int j = 0; j < probB.length; j++) {
                if (i > j) {
                    winProbability += probA[i] * probB[j];
                }
            }
        }
        // 保留三位小数
        return Math.round(winProbability * 1000.0) / 1000.0;
    }

    private static double[] calculateProbabilities(int[] dice) {
        int maxSum = Arrays.stream(dice).sum();
        double[] dp = new double[maxSum + 1];
        dp[0] = 1.0;
        for (int die : dice) {
            double[] newDp = new double[maxSum + 1];
            for (int sum = 0; sum <= maxSum; sum++) {
                if (dp[sum] > 0) {
                    for (int face = 1; face <= die; face++) {
                        newDp[sum + face] += dp[sum] / die;
                    }
                }
            }
            dp = newDp;
        }
        return dp;
    }

    public static void main(String[] args) {
        System.out.println(solution(1, 3, new int[]{8}, new int[]{2, 3, 4}));
    }
}

试题4:小C和小U

问题描述: 小C和小U一直相互喜欢着,今天他们终于有机会表达对彼此的心意。

小C有三个区间:[l_1, r_1], [l_2, r_2], 和 [l_3, r_3]。小C和小U将分别从这些区间中选择一个自己最喜欢的区间,但这两个区间不能相同。

接着,他们会在自己喜欢的区间内选择一个数,并且这个数还要能够在对方的区间内找到。为了讨对方欢心,他们希望选择的两个数的和尽可能大。

你的任务是帮助小C和小U找到这两个数的和的最大值。如果不存在这样的两个数,输出 -1。

python 复制代码
def solution(l1: int, r1: int, l2: int, r2: int, l3: int, r3: int) -> int:
    # 初始化最大和为 -1
    max_sum = -1
    
    # 定义区间数组
    intervals = [(l1, r1), (l2, r2), (l3, r3)]
    
    # 遍历所有可能的区间组合
    for i in range(3):
        for j in range(3):
            if i != j:  # 确保两个区间不相同
                # 选择区间 i 和区间 j
                (l_i, r_i) = intervals[i]
                (l_j, r_j) = intervals[j]
                
                # 在区间 i 中选择一个数
                for x in range(l_i, r_i + 1):
                    # 在区间 j 中选择一个数
                    for y in range(l_j, r_j + 1):
                        # 检查 x 是否在区间 j 中,y 是否在区间 i 中
                        if l_j <= x <= r_j and l_i <= y <= r_i:
                            # 更新最大和
                            max_sum = max(max_sum, x + y)
    
    return max_sum

if __name__ == '__main__':
    print(solution(1, 3, 2, 4, 4, 6) == 8)
    print(solution(1, 2, 2, 3, 3, 4) == 6)
    print(solution(10, 20, 15, 25, 30, 40) == 40)

试题5:小C的圆构造

问题描述: 在平面直角坐标系内,有一个点 P(x, y)。我们需要构造两个圆,这两个圆必须同时满足以下两个条件:

圆与 x 轴和 y 轴都相切。 圆经过点 P。 显然,这样的圆有两个合法解。请你输出这两个解的圆的半径,要求按照从小到大的顺序输出,结果保留两位小数。

python 复制代码
def solution(x: int, y: int) -> list:
    # 计算二次方程的系数
    a = 1
    b = -2 * (x + y)
    c = x**2 + y**2
    
    # 解二次方程 r^2 - 2(x+y)r + (x^2 + y^2) = 0
    discriminant = b**2 - 4*a*c
    r1 = (-b + discriminant**0.5) / (2 * a)
    r2 = (-b - discriminant**0.5) / (2 * a)
    
    # 返回两个半径,按从小到大的顺序
    return [f'{min(r1, r2):.2f}', f'{max(r1, r2):.2f}']

if __name__ == '__main__':
    print(solution(1, 2) == ['1.00', '5.00'])
    print(solution(3, 4) == ['2.10', '11.90'])
    print(solution(5, 6) == ['3.25', '18.75'])

试题6:小C的好数

问题描述: 小C对"好数"非常感兴趣,她定义一个不含前导零的正整数为"好数",如果它的所有数位最多包含两种不同的数字。例如,数字 23,2323,9,111,和 101 都是好数。现在小C想知道,从1到n之间有多少个好数。

例如:当n=110时,所有的1位数、2位数,以及一些3位数(如 100, 101)都是好数,一共有102个

python 复制代码
def solution(n: int) -> int:
    count = 0  # 初始化好数的计数器
    
    for num in range(1, n + 1):
        num_str = str(num)            # 将数字转换为字符串
        unique_digits = set(num_str)  # 获取数字中不同的字符
        if len(unique_digits) <= 2:   # 如果不同字符数量 <= 2
            count += 1                 # 计数器加1
            
    return count
 
if __name__ == '__main__':
    print(solution(110) == 102)        # 输出: True
    print(solution(1000) == 352)       # 输出: True
    print(solution(1) == 1)            # 输出: True
相关推荐
查理零世6 分钟前
算法竞赛之差分进阶——等差数列差分 python
python·算法·差分
ByteBlossom6662 小时前
MDX语言的语法糖
开发语言·后端·golang
计算机学姐2 小时前
基于微信小程序的驾校预约小程序
java·vue.js·spring boot·后端·spring·微信小程序·小程序
小猿_002 小时前
C语言程序设计十大排序—插入排序
c语言·算法·排序算法
沈霁晨3 小时前
Ruby语言的Web开发
开发语言·后端·golang
DanceDonkey3 小时前
@RabbitListener处理重试机制完成后的异常捕获
开发语言·后端·ruby
平凡的运维之路3 小时前
vsftpd虚拟用户部署
后端
叫我:松哥4 小时前
基于Python django的音乐用户偏好分析及可视化系统设计与实现
人工智能·后端·python·mysql·数据分析·django
熊文豪5 小时前
深入解析人工智能中的协同过滤算法及其在推荐系统中的应用与优化
人工智能·算法
Leaf吧6 小时前
springboot 配置多数据源以及动态切换数据源
java·数据库·spring boot·后端