力扣题目链接:https://leetcode-cn.com/problems/maximum-subarray/
如果数组中有正数,则所求最大子数组一定是正数为首位。
所以当前和如果为负数时直接归零。得到一个时间复杂度为O(n)的java解决方法如下:
class Solution {
public int maxSubArray(int[] nums) {
int csum = 0;
int max = -10000;
//int flag = 0;
for(int i = 0; i < nums.length; i++){
if(csum < 0){
csum = 0;
}
csum += nums[i];
if(csum>max){
max = csum;
//flag = i;
}
}
//System.out.println(flag);
return max;
}
}
如果用分治法,可以得到时间复杂度为O(nlogn)的方法:
class Solution {
public int max(int a, int b, int c){
int max = a;
if(max<b){
max = b;
}
if(c>max)
max = c;
return max;
}
public int biSearch(int[] nums, int left, int right){
if (left == right)
{
return nums[left];
}
int left_max = 0;
int right_max = 0;
int mid_max = 0;
int max = 0;
int mid = (right + left)/2;
left_max = biSearch(nums, left, mid);
right_max = biSearch(nums, mid+1, right);
mid_max = midMax(nums, right, left, mid);
max = max(left_max, right_max, mid_max);
return max;
}
public int midMax(int[] nums, int left, int right, int mid){
int left_max = Integer.MIN_VALUE;
int sum = 0;
for(int i = mid; i>=left; i--){
sum += nums[i];
if(sum > left_max){
left_max = sum;
}
}
int right_max = Integer.MIN_VALUE;
sum = 0;
for(int i = mid+1; i<=right; i++){
sum += nums[i];
if(sum > right_max){
right_max = sum;
}
}
return (left_max + right_max);
}
public int maxSubArray(int[] nums) {
int csum = 0;
int max = 0;
max = biSearch(nums, 0, nums.length-1);
return max;
}
}
用java这样写报错了,暂时不知道怎么debug,改为用C++写:
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
int result = INT_MIN;
int numsSize = int(nums.size());
result = maxSubArrayHelper(nums, 0, numsSize - 1);
return result;
}
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);
//注意这里应是mid + 1,否则left + 1 = right时,会无限循环
int rightSum = maxSubArrayHelper(nums, mid + 1, right);
int midSum = findMaxCrossingSubarray(nums, left, mid, right);
int result = max(leftSum, rightSum);
result = max(result, midSum);
return result;
}
int findMaxCrossingSubarray(vector<int> &nums, int left, int mid, int right)
{
int leftSum = INT_MIN;
int sum = 0;
for (int i = mid; i >= left; i--)
{
sum += nums[i];
leftSum = max(leftSum, sum);
}
int rightSum = INT_MIN;
sum = 0;
//注意这里i = mid + 1,避免重复用到nums[i]
for (int i = mid + 1; i <= right; i++)
{
sum += nums[i];
rightSum = max(rightSum, sum);
}
return (leftSum + rightSum);
}
};
动态规划法:
class Solution {
public int maxSubArray(int[] nums) {
int[] cmax = new int[nums.length];
cmax[0] = nums[0];
int max = nums[0];
for(int i = 1; i < nums.length; i++){
cmax[i] = Math.max(cmax[i-1]+nums[i], nums[i]);
// 当前最优等于前一个最优加当前值或者当前值本身
max = Math.max(cmax[i],max);
// 总的最优解=先前最优解和当前最优解的最优值
}
return max;
}
}