首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >关于动态规划(Dynamic Programming)

关于动态规划(Dynamic Programming)

作者头像
Wu_Candy
发布2022-07-04 20:38:58
发布2022-07-04 20:38:58
3440
举报
文章被收录于专栏:无量测试之道无量测试之道
这是无量测试之道的第192篇原创

Dynamic Programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems, solving each of those subproblems just once, and storing their solutions.

  1. 将复杂的原问题拆解成若干个简单的子问题
  2. 每个子问题仅仅解决1次,并保存它们的解
  3. 最后推导出原问题的解
可以用动态规划来解决的问题,通常具备2个特点
  • 最优子结构(最优化原理):通过求解子问题的最优解,可以获得原问题的最优解
  • 无后效性
    1. 某阶段的状态一旦确定,则此后过程的演变不再受此前各状态及决策的影响(未来与过去无关)
    2. 在推导后面阶段的状态时,只关心前面阶段的具体状态值,不关心这个状态是怎么一步步推导出来的

练习:连续子数组的最大和

一开始的思绪

看到这个题目的时候,不知道动态规划的时候,就开始去思考怎么解,总是会胡思乱想,然后没法细致的去拆解问题,从而没有一个着力点。

动态规划的解题思路

1.状态定义

假设 dp(i) 是以 nums[i] 结尾的最大连续子序列和(nums是整个序列)

dp是对(Dynamic Programming)简写

  • 以 nums[0] –2 结尾的最大连续子序列是 –2,所以 dp(0) = –2
  • 以 nums[1] 1 结尾的最大连续子序列是 1,所以 dp(1) = 1
  • 以 nums[2] –3 结尾的最大连续子序列是 1、–3,所以 dp(2) = dp(1) + (–3) = –2
  • 以 nums[3] 4 结尾的最大连续子序列是 4,所以 dp(3) = 4
  • 以 nums[4] –1 结尾的最大连续子序列是 4、–1,所以 dp(4) = dp(3) + (–1) = 3
  • 以 nums[5] 2 结尾的最大连续子序列是 4、–1、2,所以 dp(5) = dp(4) + 2 = 5
  • 以 nums[6] 1 结尾的最大连续子序列是 4、–1、2、1,所以 dp(6) = dp(5) + 1 = 6
  • 以 nums[7] –5 结尾的最大连续子序列是 4、–1、2、1、–5,所以 dp(7) = dp(6) + (–5) = 1
  • 以 nums[8] 4 结尾的最大连续子序列是 4、–1、2、1、–5、4,所以 dp(8) = dp(7) + 4 = 5

2.状态转移方程

  • 如果 dp(i – 1) ≤ 0,那么 dp(i) = nums[i]
  • 如果 dp(i – 1) > 0,那么 dp(i) = dp(i – 1) + nums[i]

3.设定初始状态和确定最终的解

  • 初始状态
dp(0) 的值是 nums[0]
  • 最终的解
最大连续子序列和是所有 dp(i) 中的最大值 max { dp(i) },i ∈ [0, nums.length)

总结:整个核心就在状态转移方程

本题的状态转移方程就很清晰,如果dp(i-1)是负数那么dp(i)就不要和之前的连续数组合在一起。如果是正数,那就合在一起。因为每一步都是最优解,所以结果就是max { dp(i) }。

代码实现

代码语言:javascript
复制
func maxSubarray(nums: [Int]) -> Int {
        if nums.count  == 0  { return 0 }
        var dp = [Int](repeating: nums[0], count: nums.count)
        var maxValue = dp[0]
        for (i, value) in nums.enumerated() {
            if i >= 1 {
                let prev = dp[i - 1]
                if prev > 0 {
                    dp[i] = dp[i-1] + value
                } else {
                    dp[i] = value
                }
            }
            maxValue = max(maxValue, dp[i])
        }
        
        return maxValue
    }

上面这个算法的时间复杂度是O(n), 空间复杂度也是O(n)。因为记录了每一个dp(i)

代码语言:javascript
复制
 func maxSubArray(_ nums: [Int]) -> Int {
        if nums.count  == 0  { return 0 }
        var maxValue = nums[0]
        var dp = nums[0]
        for i in 1..<nums.count {
            if dp > 0 {
                dp = dp + nums[i]
            } else {
                dp = nums[i]
            }
            maxValue = max(maxValue, dp)
        }
        return maxValue
    }

这个算法的时间复杂度是O(n), 空间复杂度也是O(1)。因为本题不需要记录之前的值,对上面一个算法的优化。

end

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 无量测试之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 可以用动态规划来解决的问题,通常具备2个特点
  • 练习:连续子数组的最大和
  • 动态规划的解题思路
    • 1.状态定义
      • 假设 dp(i) 是以 nums[i] 结尾的最大连续子序列和(nums是整个序列)
    • dp是对(Dynamic Programming)简写
    • 2.状态转移方程
    • 3.设定初始状态和确定最终的解
    • 总结:整个核心就在状态转移方程
  • 代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档