标签(空格分隔): leetcode
- 原题
分析:
题目要求在一个连续数组中找到一个子数组,是的子数组的元素的和最大。- 可以使用暴力解答, n 个数一共有 C2n 种选择,分别计算这 C2n 种选择的结果然后求最大值,但是时间复杂度 O(n2) ,这道题不通过。。
- 可以使用分治算法:
>
- 假设数组A的low, mid, high分别表示数组相应的坐标,然后,数组的最大子数组有3种情况,也就是
子数组在A[low,mid]中,
子数组在A[mid+1, high]中,
子数组在A[low, high]中 - 然后在上面那三种情况中,继续可以分为同样的3种情况,也就是子问题和原问题有一样的结构。
在这种情况下,时间复杂度有主定理:
T(n)=aT(n/b)+f(n)
这里将原问题分解为 2 个 n/2 的问题
时间复杂度 O(nlgn)
但是。。。。。这个在leetcode这道题上是超时的。。
- 使用动态规划:
如果用函数 f(i)表示以第 i个数字结尾的子数组的最大和,那么我们需要求出 max[f(i)],其中 0 <= i < n。我们可用如下边归公式求 f(i):
f(i)={nums[i]f[i−1]+nums[i]i=0orf[i−1]<0i>0andf[i−1]>0
这个公式的意义:当以第 i-1 个数字结尾的子数组中所有数字的和小于 0 时,如果把这个负数与第 i 个数累加,得到的结果比第 i 个数字本身还要小,所以这种情况下以第 i 个数字结尾的子数组就是第 i 个数字本身。如果以第 i-1 个数字结尾的子数组中所有数字的和大于 0,与第 i 个数字累加就得到以第 i 个数字结尾的子数组中所有数字的和。
还要考虑特殊情况全是负号的情况就可以
- 代码:
- 动态规划:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int MaxSum = 0;
int CurSum = 0;
bool hasPositive = false;
int max = INT_MIN;
for (int i = 0; i < nums.size(); i++){
if (nums[i] > 0){
hasPositive = true;
break;
}
if (nums[i] > max){
max = nums[i];
}
}
if (!hasPositive){
return max;
}
for (int i = 0; i < nums.size(); i++){
CurSum += nums[i];
if (CurSum > MaxSum){
MaxSum = CurSum;
}
if (CurSum < 0){
CurSum = 0;
}
}
return MaxSum;
}
};
- 分治的(超时)
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
using namespace std;
struct DATA {
int low;
int high;
int sum;
DATA(int low, int high, int sum) {
this->low = low;
this->high = high;
this->sum = sum;
}
};
DATA findMaxCrossSum(vector<int> A, int low, int mid, int high) {
int left_sum = INT_MIN;
int sum = 0;
int max_left = -1;
for (int i = mid; i >= low; i--) {
sum += A[i];
if (sum > left_sum) {
left_sum = sum;
max_left = i;
}
}
int right_sum = INT_MIN;
int max_right = -1;
sum = 0;
for (int i = mid + 1; i <= high; i++) {
sum += A[i];
if (sum > right_sum) {
right_sum = sum;
max_right = i;
}
}
return DATA(max_left, max_right, left_sum + right_sum);
}
DATA findMaxSub(vector<int> A, int low, int high) {
if (high == low) {
return DATA(low, low, A[low]);
}
else {
int mid = (low + high) / 2;
DATA left = findMaxSub(A, low, mid);
DATA right = findMaxSub(A, mid + 1, high);
DATA cross = findMaxCrossSum(A, low, mid, high);
if (left.sum >= right.sum && left.sum >= cross.sum)
return left;
if (right.sum >= left.sum && right.sum >= cross.sum)
return right;
return cross;
}
}
int maxSubArray(vector<int>& nums) {
int sum = 0;
bool hasNegative = false;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] < 0)
hasNegative = true;
sum += nums[i];
}
if (!hasNegative)
return sum;
DATA ans = findMaxSub(nums, 0, nums.size() - 1);
return ans.sum;
}
int main() {
vector<int> v{ -2,1,-3,4,-1,2,1,-5,4 };
cout << maxSubArray(v) << endl;
system("pause");
return 0;
}
本文探讨了寻找连续数组中具有最大和的子数组问题。介绍了暴力解法、分治算法和动态规划三种方法,并详细解释了动态规划的实现过程及代码示例。
754

被折叠的 条评论
为什么被折叠?



