第二题 #53
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-subarray
1、暴力解法 :时间复杂度O(n^2)空间复杂度O(1)
第一遍遍历数组,以每个数组的一个元素为其起始值
第二遍遍历数组,求以某个元素为起始值的最大连续数组和的值
注意:返回的最大值的初始值要设置为INT_MIN
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int max_ans = INT_MIN;
int nums_size = nums.size();
for( int i=0; i<nums_size; i++){
int sum = 0;
for( int j=i; j<nums_size; j++){
sum += nums[j];
if(sum>max_ans)
max_ans = sum;
}
}
return max_ans;
}
};
2、动态规划法 时间复杂度O(n)、空间复杂度O(n) (优化后使用注释的代码空间复杂度为O(1)
用 f(i)代表以第 i个数结尾的所有连续子数组的最大和,0≤i≤n−1max {f(i)},我们只需要求出每个位置的 f(i),然后返回 f 数组中的最大值即可。我们可以考虑nums[i]单独成为一段还是加入f(i-1)对应的那一段,这取决于nums[i]和 f(i-1)+nums[i] 的大小,所以有f(i) = max { f(i - 1) +nums[i],nums[i]} 。
我们可以只用一个变量 pre 来维护对于当前 f(i)的f(i−1) 的值是多少,从而让空间复杂度降低到 O(1)。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int max_ans = INT_MIN;
int nums_size = nums.size();
vector<int> f(nums_size);
f[0] = nums[0];
max_ans = f[0];
for( int i=1; i<nums_size; i++){
f[i] = max(f[i-1]+nums[i], nums[i]);
max_ans = max(f[i], max_ans);
}
/*
int pre = 0 ;
for(const auto &x : nums){
pre = max( pre + x, x);
max_ans = max( pre, max_ans);
}
*/
return max_ans;
}
};
3、分治法 递归求最大值:时间复杂度O(nlog(n))、空间复杂度O(log(n))
将数组从中间分开,最大子序一共存在三种情况:
①在数组的左半部分
②在数组的右半部分
③跨域中间节点部分。
然后对分开的数组左右两部分进行递归相同操作。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int nums_size = nums.size();
int ans = INT_MIN;
ans = maxSubArrayHelper(nums, 0 , nums_size-1);
return ans;
}
int maxSubArrayHelper(vector<int>& nums, int left, int right){
if(left==right) return nums[left];
int mid = (left+right)/2;
int LeftSum = maxSubArrayHelper(nums, left, mid);
int RightSum = maxSubArrayHelper(nums, mid+1, right);
int MidSum = maxSubArrayMid(nums, left, mid, right);
int result = max(LeftSum,RightSum);
return max(result,MidSum);
}
int maxSubArrayMid(vector<int>& nums, int left, int mid, int right){
int leftSum = INT_MIN;
int sums=0;
for(int i = mid; i >=left; i--){
sums += nums[i];
leftSum = max(leftSum ,sums);
}
int rightSum = INT_MIN;
sums=0;
for(int i = mid+1; i <=right; i++){
sums += nums[i];
rightSum = max(rightSum,sums);
}
return rightSum+leftSum;
}
};
4、贪心算法:时间复杂度O(n)空间复杂度O(1)
从数组的左边开始向友遍历迭代,如果累加的和小于0则重新开始累加;
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int nums_size = nums.size();
int ans = INT_MIN;
int sum = 0;
for(int i = 0; i < nums_size; i++){
sum += nums[i];
ans = max(sum , ans);
if(sum<0)
sum = 0;
}
return ans;
}
};