本题适合动态规划的原因
本题接的重点在
-
理解题意
题目只要求返回结果,不要求得到最大的连续子数组是哪一个,一般用DP解决 -
如何定义子问题(如何定义状态)
存在不确定性的子问题 like:(经过 —— 位置不确定 —— start end不确定)
确定的子问题 like:
-
什么是 无后效性
为了保证计算子问题能够按照顺序、不重复地进行,动态规划要求已经求解的子问题不受后续阶段的影响。这个条件也被叫做无后效性。换言之,动态规划对状态空间的遍历构成一张有向无环图,遍历就是该有向无环图的一个拓扑序。有向无环图中的节点对应问题中的状态,图中的边则对应状态之间的转移,转移的选取就是动态规划中的决策。
题解1 不标准动态规划(标准参考labuladong)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
const int s = nums.size();
if(1 == s) return nums[0];
// meaning : dp[i] : 以 nums[i]结尾的 最大子数组和
vector<int> dp(s);
// base case
dp[0] = nums[0];
// 转移方程
// 根据题意,i及 i以前的 可能的最大值 要么是nums[i]本身,要么是 i前最大的值 累加上 此位置的值
// 不标准: dp[s-1]不是最后的结果
for(int i=1; i < s; i++)
dp[i] = max(nums[i], nums[i] + dp[i-1]);
int maxV = INT_MIN;
for(auto & i : dp){
maxV = max(maxV, i);
}
return maxV;
}
};
题解2 优化DP(前缀和)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
const int s = nums.size();
if(1 == s) return nums[0];
int res = INT_MIN;
int pre = 0;
for(int i=0; i < s; i++){
pre = max(nums[i], nums[i]+pre);
res = max(res, pre);
}
return res;
}
};
题解3 分治(有时间撸)
不仅可以解决区间 [0,n−1][0, n-1][0,n−1],还可以用于解决任意的子区间 [l,r][l,r][l,r] 的问题。如果我们把 [0,n−1][0, n-1][0,n−1] 分治下去出现的所有子区间的信息都用堆式存储的方式记忆化下来,即建成一棵真正的树之后,我们就可以在 O(logn) 的时间内求到任意区间内的答案,我们甚至可以修改序列中的值,做一些简单的维护,之后仍然可以在 O(logn)的时间内求到任意区间内的答案,对于大规模查询的情况下,这种方法的优势便体现了出来。这棵树就是上文提及的一种神奇的数据结构——线段树