伴学笔记2

150 阅读4分钟

题目解析

题目:小R和小S在探险过程中发现了一个装满金币的宝箱。宝箱里有N枚金币,他们决定按照以下规则来分配:

  1. 小R和小S轮流选取金币,且小R先选。
  2. 如果当前剩余的金币数量为偶数时,可以选择拿走一半的金币,或者只拿走一枚金币。
  3. 如果当前剩余的金币数量为奇数时,只能拿走一枚金币。

两人都会采取最优策略来获取更多的金币。现在,你需要计算小R和小S最终各自拿走的金币数量。

思路

  1. 动态规划:我们可以使用动态规划来解决这个问题。定义一个二维数组dp,其中dp[i][0]表示当小R面对i枚金币时,他能拿到的最大金币数,dp[i][1]表示小S能拿到的最大金币数。

  2. 状态转移

    • 当金币数为奇数时,小R只能拿走一枚金币,剩下的金币数变为偶数,轮到小S拿。此时,小R能拿的金币数为dp[i-1][1] + 1,小S则根据dp[i-1][0]来决定自己的最优策略。
    • 当金币数为偶数时,小R可以选择拿走一半或者一枚金币。我们需要比较这两种情况下小R能拿到的金币数,选择最大的那个。对于拿走一半的情况,剩下的金币数为i//2,是偶数,小S会根据dp[i//2][0]来决定自己的最优策略。
  3. 初始化dp[0][0] = 0, dp[0][1] = 0,表示没有金币时,两人都拿不到金币。

图解
(由于文字表述的限制,无法直接给出图解,但可以通过代码逻辑来理解动态规划的状态转移过程。)

代码详解

python复制代码
	def solution(N: int) -> list:

	    dp = [[0, 0] for _ in range(N + 1)]

	    for i in range(1, N + 1):

	        if i % 2 == 1:

	            dp[i][0] = dp[i - 1][1] + 1

	            dp[i][1] = dp[i - 1][0]

	        else:

	            take_one = dp[i - 1][1] + 1

	            take_half = dp[i // 2][1] + i // 2

	            if take_one > take_half:

	                dp[i][0] = take_one

	                dp[i][1] = dp[i - 1][0]

	            else:

	                dp[i][0] = take_half

	                dp[i][1] = dp[i // 2][0]

	    return [dp[N][0], dp[N][1]]

知识总结

本次刷题让我深刻理解了动态规划在解决策略优化问题中的应用。动态规划通过将问题分解为子问题,并存储子问题的解来避免重复计算,从而提高了算法的效率。对于本题,通过定义dp数组来记录每个状态下的最优解,并根据状态转移方程进行求解,最终得到了小R和小S各自能拿到的最大金币数。

对于入门同学,我建议先从简单的动态规划问题开始练习,逐步掌握动态规划的基本思想和方法。同时,要多看题解和代码实现,理解不同问题的动态规划解法之间的共性和差异。

学习计划

结合豆包MarsCode AI刷题功能,我制定了以下高效学习方法:

  1. 制定刷题计划:每天安排一定的时间进行刷题,并根据自己的掌握情况逐步增加难度。
  2. 分类练习:将题目按照知识点进行分类,有针对性地进行练习,以巩固和加深对知识点的理解。
  3. 利用错题:对于做错的题目,要认真分析错误原因,并重新练习相关知识点,直到完全掌握。
  4. 定期总结:每周或每月对所学知识点进行总结和梳理,形成自己的知识体系。

工具运用

豆包MarsCode AI刷题功能为我提供了丰富的题目资源和智能的刷题建议。为了更好地利用这一功能,我将其与其他学习资源相结合:

  1. 结合视频教程:在刷题前,先观看相关的视频教程,了解题目的基本思路和解法。
  2. 查看题解:对于难以理解的题目,我会查看其他用户的题解和代码实现,以拓宽自己的解题思路。
  3. 参与讨论:在刷题过程中,积极参与讨论区,与其他用户交流心得和经验,共同进步。

通过以上方法,我相信自己能够在刷题过程中不断提高自己的编程能力和算法水平。