当前位置: 首页 > news >正文

Python 动态规划(DP)套路总结

Python 动态规划(DP)套路总结

在解决算法问题时,动态规划(DP) 是一种非常常见的优化技巧,它可以通过保存子问题的结果来避免重复计算,从而减少时间复杂度。Python 提供了非常方便的语法特性,使得实现动态规划变得相对简单。下面是一些常见的 Python 语法DP 解题套路

1. Python 语法和技巧

1.1 列表初始化

在 Python 中,动态规划通常需要一个数组来存储子问题的解,常见的初始化方法有:

  • 一维数组

    dp = [0] * n  # 初始化一个长度为 n 的数组,元素均为 0
    
  • 二维数组

    dp = [[0] * m for _ in range(n)]  # 初始化一个 n x m 的二维数组,元素均为 0
    
  • 处理边界情况
    如果问题涉及到无效值(例如负无穷),可以初始化为非常小的数字:

    dp = [-float('inf')] * n  # 初始化为负无穷
    

1.2 枚举排列

  • 枚举排列:通常用于动态规划中,确定所有的选择路径:

    for i in range(n):
        for j in range(i, n):  # 遍历子数组
            # 在这里进行状态转移
    
  • 利用索引生成排序后的顺序

    sorted_idx = sorted(range(len(arr)), key=lambda i: arr[i])  # 排序并记录原始索引
    

2. 动态规划(DP)解题套路

2.1 状态定义

首先,需要定义一个或多个状态,表示每个子问题的结果。常见的状态定义如下:

  • dp[i] 表示前 i 个元素的最大和或最小值
  • dp[i][j] 表示在第 i 个位置选择了 j 种操作后的最优解
  • 对于某些题目,可能需要额外记录其他信息,如最大或最小值、索引等。

2.2 状态转移方程

根据题目要求,写出从一个状态转移到另一个状态的递推公式。一般来说,转移方程会根据前一个状态的结果来更新当前状态。

2.3 边界条件

动态规划通常从小的子问题开始,需要明确边界条件:

  • dp[0] 可能是初始化的最小值。
  • dp[1] 可能是初始值或第一个元素的特殊处理。

2.4 最终解的选择

在动态规划的过程中,我们最终希望找到全局最优解(例如最大值或最小值)。通常,我们需要通过 max(dp)min(dp) 来获取结果。


3. 题目解析与动态规划解法

题目:1186. 删除一次得到子数组最大和

题目描述

给定一个整数数组 arr,返回它的某个非空子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。换句话说,你可以从原数组中选出一个子数组,并可以决定要不要从中删除一个元素(只能删一次哦),删除后该子数组中至少应当有一个元素。

示例
arr = [1,-2,0,3]
输出: 4

解释:

  • 我们可以选择子数组 [1, -2, 0, 3],删除 -2,得到 [1, 0, 3],最大和为 4
解法思路

对于这个问题,我们可以使用 动态规划(DP) 来处理。考虑两种情况:

  1. 不删除任何元素 的情况下,子数组的最大和。
  2. 删除一个元素后,子数组的最大和。

1. 定义状态

  • dp[i][0]:表示到第 i 个元素为止,不删除任何元素时的最大和。
  • dp[i][1]:表示到第 i 个元素为止,删除一个元素后的最大和。

2. 状态转移方程

  • dp[i][0]:可以选择加入当前元素,或者从当前元素开始一个新的子数组:
    dp[i][0] = max(arr[i], dp[i-1][0] + arr[i])
    
  • dp[i][1]:可以选择删除当前元素,或者删除前一个元素并加上当前元素:
    dp[i][1] = max(dp[i-1][0], dp[i-1][1] + arr[i])
    

3. 边界条件

  • dp[0][0] = arr[0],表示子数组只有第一个元素的情况。
  • dp[0][1] = -inf,表示第一个元素不能删除,因为至少要保留一个元素。

4. 最终解

我们需要考虑两种情况的最大值:

  • dp[i][0] 表示不删除元素的最大和。
  • dp[i][1] 表示删除一个元素后的最大和。

最终的解是 max(max(dp[i][0] for i in range(n)), max(dp[i][1] for i in range(n)))
在这里插入图片描述

代码实现
class Solution:
    def maximumSum(self, arr: List[int]) -> int:
        n = len(arr)
        
        # 初始化 dp 数组,初始值为负无穷
        dp = [[-2e9, -2e9] for _ in range(n)]
        
        # 初始化第一个元素的情况
        dp[0][0] = arr[0]
        dp[0][1] = float('-inf')  # 删除第一个元素不合法
        
        # 动态规划遍历
        for i in range(1, n):
            dp[i][0] = max(arr[i], dp[i - 1][0] + arr[i])  # 不删除
            dp[i][1] = max(dp[i - 1][0], dp[i - 1][1] + arr[i])  # 删除一个元素
        
        # 返回最大结果
        return max(max(dp[i][0] for i in range(n)), max(dp[i][1] for i in range(n)))
解析:
  1. 初始化:我们初始化了 dp 数组,并为第一个元素设定了边界条件。
  2. 状态转移:我们通过遍历 arr 数组,逐步计算 dp[i][0]dp[i][1],表示不删除元素和删除元素后的最大和。
  3. 返回结果:最后返回 dp 数组中最大的值,即为子数组的最大和。

时间复杂度与空间复杂度:

  • 时间复杂度O(n),我们只遍历了一次数组,并进行常数时间的计算。
  • 空间复杂度O(n),需要一个大小为 n 的动态规划数组。

总结

动态规划(DP)是解决子问题最优解的强大工具。在此题中,我们利用了动态规划的状态定义转移方程来解决删除一次元素后的子数组最大和问题。在处理此类问题时,理解状态定义与转移方程至关重要,它能够帮助我们高效地得出最终的最优解。
两种状态 没有行使权力的最大数组和 行使权力后的最大数组和
没有行使权力可以另起炉灶一个新的或者继承之前的
行使权力的可以继承之前的,或者行使权力不删集成没有行使权力的

相关文章:

  • UE5从入门到精通之如何创建自定义插件
  • (数据结构)双向链表
  • 2025-03-09 学习记录--C/C++-PTA 习题11-1 输出月份英文名
  • BEVDepth: Acquisition of Reliable Depth for Multi-view 3D Object Detection 论文阅读
  • 代码随想录算法训练营第八天|Leetcode 151.翻转字符串里的单词 卡码网:55.右旋转字符串 字符串总结 双指针回顾
  • 基于Spring3的抽奖系统
  • 通义千问:Qwen2.5-0.5B模型架构解释
  • 绘制列线图并解释线性模型的Python包-nomogram-explainer(记我的第一个pypi项目)
  • 配置多区域OSPF,配置OSPF手动汇总,配置OSPF特殊区域
  • IO多路复用实现并发服务器
  • 电路研究10——MPU6050电路搭建
  • InDraw6.2.3 | 甾体、核苷、黄酮类化合物实现简称命名
  • 模板注入Smarty
  • 《C++ primer》第六章
  • Linux基本操作指令3
  • 用K8S部署Milvus服务
  • 设备树的概念
  • 【网络编程】简单的网络服务器设计
  • 编程题-计算器(中等)
  • 耘锄、铧式犁、畦作
  • 提高网站seo/展示型网站有哪些
  • 北京景网站建设/竞价推广的企业
  • 手机 网站编辑器/宁波seo搜索引擎优化
  • 济宁疫情最新消息/常用的seo查询工具
  • 升腾d9116 做网站/营口建网站的公司
  • 贵州网站推广电话/最新长尾关键词挖掘