动态规划(英语:Dynamic programming,简称 DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。动态规划往往用于优化递归问题,例如斐波那契数列,如果运用递归的方式来求解会重复计算很多相同的子问题,利用动态规划的思想可以减少计算量。
通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,具有天然剪枝的功能,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
原问题可以拆分成若干不同部分的子问题,子问题也可以进一步的拆分为子问题(即重叠子问题),而且每一个分枝的子问题结构应该相同(即最优子结构),通过求解这些子问题可以达到求解原问题的目的。
动态规划希望的问题解决模式为: dp[i]=fn(dp[i-1],num[i]), 即 : 给定原数据列表num,动态规划列表 dp中 ,dp[i] 的值应由dp[i-1]和num[i]通过某种固定的函数关系得到
LeetCode:剑指 Offer 42. 连续子数组的最大和 输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。 要求时间复杂度为O(n)。 示例1: 输入: nums = [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 提示:
1 <= arr.length <= 10^5-100 <= arr[i] <= 100问题 : 连续子数组的最大和 分解: 求解每个子数组的最大和,比较,取最大值 由于要求连续子数组,所以只需记录以元素 nums[i] 为结尾的连续子数组最大和的值,然后再比较即可。 子问题:求以元素 nums[i] 为结尾的连续子数组最大和的值 原问题与子问题及num[i]之间的关系(转移方程): dp[i] = nums[i] + max(dp[i - 1], 0);
状态定义: 设动态规划列表 dp ,dp[i]代表以元素 nums[i]为结尾的连续子数组最大和。 -为何定义最大和 dp[i]中必须包含元素 nums[i] :保证 dp[i] 递推到 dp[i+1]的正确性;如果不包含 nums[i],递推时则不满足题目的 连续子数组 要求。
转移方程: 若 dp[i−1]≤0 ,说明 dp[i - 1] 对 dp[i] 产生负贡献,即 dp[i-1] + nums[i]还不如 nums[i]本身大。 -当 dp[i - 1] > 0 时:执行 dp[i] = dp[i-1] + nums[i]; -当 dp[i−1]≤0 时:执行 dp[i] = nums[i]; -初始状态: dp[0] = nums[0],即以 nums[0] 结尾的连续子数组最大和为 nums[0] 。
返回值: 返回 dpdp 列表中的最大值,代表全局最大值。 空间复杂度降低: 由于 dp[i]dp[i] 只与 dp[i-1]dp[i−1] 和 nums[i]nums[i] 有关系,因此可以将原数组 numsnums 用作 dpdp 列表,即直接在 numsnums 上修改即可。 由于省去 dpdp 列表使用的额外空间,因此空间复杂度从 O(N)O(N) 降至 O(1)O(1) 。 复杂度分析:
时间复杂度 O(N): 线性遍历数组 numsnums 即可获得结果,使用 O(N)时间。
空间复杂度 O(1): 使用常数大小的额外空间。
请完成你今天的优秀,明天再谈你的优秀