• 关于动态规划(Dynamic Programming)


    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、最优子结构(最优化原理):通过求解子问题的最优解,可以获得原问题的最优解

    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) }。

     
    代码实现

    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)

     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)。因为本题不需要记录之前的值,对上面一个算法的优化。

    欢迎关注【无量测试之道】公众号,回复【领取资源】
    Python编程学习资源干货、
    Python+Appium框架APP的UI自动化、
    Python+Selenium框架Web的UI自动化、
    Python+Unittest框架API自动化、

    资源和代码 免费送啦~
    文章下方有公众号二维码,可直接微信扫一扫关注即可。

    备注:我的个人公众号已正式开通,致力于测试技术的分享,包含:大数据测试、功能测试,测试开发,API接口自动化、测试运维、UI自动化测试等,微信搜索公众号:“无量测试之道”,或扫描下方二维码:

     

     添加关注,让我们一起共同成长!

  • 相关阅读:
    测试本地node包
    webpack4+react多页面架构
    身为前端开发工程师,你需要了解的搜索引擎优化SEO.
    代码改变世界 | 如何封装一个简单的 Koa
    云计算系统測试之技术概念
    Cocos2d-x3.0 从代码中获取cocostudio编辑的UI控件
    Spring使用HibernateDaoSupport操作数据
    gitlab一键安装 笔记
    【TCP/IP】IP路由选择
    ios网络学习------3 用非代理方法实现异步post请求
  • 原文地址:https://www.cnblogs.com/Wu13241454771/p/14593479.html
Copyright © 2020-2023  润新知