题目详情
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。
求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
题目分解/做题思路
根据要求 求出 每个子数组的和,然后找出最大的子数组和
怎么找单独的子数组的和?
使用动态规划,创建一个数组存放每次最大子数组的和,然后取最大值
解题方法:
动态规划
动态规划(Dynamic Programming)是一种用于解决优化问题的算法思想,通常用于具有重叠子问题和最优子结构性质的问题。它通过将问题分解为更小的子问题,并且在解决子问题时保存已经计算过的结果,以避免重复计算,从而提高算法的效率。
动态规划的核心思想是将大问题分解为小问题,并且记忆化已经解决的子问题的解,以便在需要时可以直接获取。这种方法在解决许多优化问题时非常有效,特别是当问题的解决方案依赖于子问题的解时。
动态规划的一般步骤
-
定义状态: 将原问题划分为若干子问题,并定义每个子问题的状态。状态是问题的局部解。
-
找到状态转移方程: 通过分析问题的最优子结构性质,找到状态之间的关系,即状态转移方程。这个方程描述了问题的解与其子问题的解之间的关系。
-
初始化: 初始化最基本的子问题,通常是问题规模最小的情况,作为算法的起点。
-
递推计算: 通过使用状态转移方程,从规模较小的子问题开始,逐步计算得到规模更大的问题的解。
-
保存结果: 为了避免重复计算,将每个子问题的解保存起来,以便后续直接使用。
-
解决原问题: 通过解决子问题,最终得到原问题的解。
动态规划的应用场景
-
最优化问题: 动态规划常被用于解决最优化问题,如最大值、最小值、最长路径等。例如,最大子数组和、最长递增子序列、0-1背包问题等。
-
搜索问题: 动态规划也可用于搜索问题,通过保存中间结果来避免重复搜索。如在棋盘上找最短路径、图的最短路径问题等。
-
排列组合问题: 涉及排列、组合、选择等问题时,动态规划可以帮助减少计算量。例如,找出组合数、排列数等。
-
字符串处理: 在字符串处理中,动态规划可用于解决编辑距离、最长公共子序列、正则表达式匹配等问题。
-
资源分配问题: 如任务调度、时间分配、资源分配等,动态规划可以帮助找到最优的资源分布方案。
-
游戏策略问题: 游戏中的决策和策略往往可以用动态规划来求解,如博弈问题、赌博问题等。
-
经济学问题: 动态规划也在经济学领域有广泛应用,如投资组合、成本最小化、收益最大化等。
解题步骤
class Solution {
public int maxSubArray(int[] nums) {
//动态规划思想
//创建一个dp数组;dp[i] 代表了以第 i 个元素结尾的最大子数组和
int[] dp = new int[nums.length];
dp[0] = nums[0]; //初始化dp数组,以第 0 个元素结尾的最大子数组就是它本身
int maxSum = dp[0]; //数组中最大的子数组的和,肯定再dp中,初始化为dp[0]
//从1开始遍历数组
for (int i = 1; i < nums.length; i++) {
//获取以第 i 个元素结尾的 最大子数组和
//如果以 nums[i-1] 结尾的最大子数组和为正数,则以第 i 个元素结尾的最大子数组和 = 前面最大的 + nums[i]
if(dp[i-1] > 0){
dp[i] = nums[i] + dp[i-1];
}else {
//如果以 nums[i-1] 结尾的最大子数组和为负数,那么会越加越小,则以第 i 个元素结尾的最大子数组和 =它本身 nums[i]
dp[i] = nums[i];
}
if(maxSum < dp[i]){
maxSum = dp[i];//进行比较替换
}
// 上面的 步骤可以简化为
// dp[i] = Math.max(nums[i],nums[i] + dp[i-1]);
// maxSum = Math.max(maxSum,dp[i]);
}
return maxSum;
}
}
相关标签:数组求和动态规划