目录
文章目录
- **目录**
- 📑前言
- 1.题目描述
- 2. 动态规划法
- 📑文章末尾
📑前言
本文主要是leetcode题解析,如果有什么需要改进的地方还请大佬指出⛺️
🎬作者简介:大家好,我是青衿🥇
☁️博客首页:CSDN主页放风讲故事
🌄每日一句:努力一点,优秀一点
1.题目描述
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。
动态规划的空间优化
这题是典型的动态规划题目, 最困难的点在于 dp数组的定义及下标含义用ai代表nums[i], 用f(i)代表以第i个数结尾的「连续子数组的最大和」, 网上也有很多文章介绍了是如何一步步分析来获得定义的过程的, 但我感觉对于新手来说, 可能还是多见一些类似的题目, 获得大量的经验, 这样比较有效果吧, 毕竟想研究动态规划的理论基础还是挺有难度的.
动态规划最重要的思想就是**利用上一个状态, 对于本题而言就是: 到底要不要加上上一个状态f(i-1)的信息, 这完全取决于f(i-1)的正负情况, 这样我们就能得出了动态规划的递推公式: f(i)=max{f(i−1)+ai,ai}
得到了递推公式后就可以编写代码了, 代码中的一个技巧就是对于空间复杂度的优化. 当使用动态规划只需要一个数(并不需要整个dp数组)时, 我们就没必要将整个dp数组都保存下来, 我们只需用变量来记录下我们需要的某个量即可, 这个优化方法在动态规划中还是非常常用的方法, 具体的实现参考代码.
2. 动态规划法
思路(动态规划) O(n)
状态表示:f[i]表示以nums[i]为结尾的最大连续子数组和。
状态计算:如何确定f[i]的值? 以nums[i]为结尾的连续子数组共分为两种情况:
只有nums[i]一个数,则f[i] = nums[i];
以nums[i]为结尾的多个数,则f[i] = f[i - 1] + nums[i]。
两种情况取最大值,因此状态转移方程为:f[i] = max(f[i - 1] + nums[i], nums[i])。
初始化:f[0] = nums[0]。
最后遍历每个位置的f[i],然后其中的最大值即可。
时间复杂度分析: 只遍历一次数组,O(n)
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
if (n == 0) return 0;
int[] dp = new int[n];
// base case
// 第一个元素前面没有子数组
dp[0] = nums[0];
// 状态转移方程
for (int i = 1; i < n; i++) {
dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]);
}
// 得到 nums 的最大子数组
int res = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}