首页 > 试题广场 >

给定一个长度为N的整数数组(元素有正有负),求所有元素之和最

[问答题]
给定一个长度为N的整数数组(元素有正有负),求所有元素之和最大的一个子数组。分析算法时间复杂度。(子数组的定义:一个或连续多个数组中元素组成一个子数组

剑指Offer-连续子数组的最大和

package Array;
/**
 * 连续子数组的最大和
 * 在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?
 * 例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。(子向量的长度至少是1)
 * 思路:
 *   F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变
     F(i)=max(F(i-1)+array[i] , array[i])
     res:所有子数组的和的最大值
     res=max(res,F(i))
     如数组[6, -3, -2, 7, -15, 1, 2, 2]
     初始状态:
     F(0)=6
     res=6
     i=1:
     F(1)=max(F(0)-3,-3)=max(6-3,3)=3
     res=max(F(1),res)=max(3,6)=6
     i=2:
     F(2)=max(F(1)-2,-2)=max(3-2,-2)=1
     res=max(F(2),res)=max(1,6)=6
     i=3:
     F(3)=max(F(2)+7,7)=max(1+7,7)=8
     res=max(F(2),res)=max(8,6)=8
     i=4:
     F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7
     res=max(F(4),res)=max(-7,8)=8
     以此类推
     最终res的值为8
 */
public class Solution01 {
    public static void main(String[] args) {
        int[] arr = {6,-3,-2,7,-15,1,2,2};
        System.out.println(FindGreatestSumOfSubArray(arr));
    }
    public static int FindGreatestSumOfSubArray(int[] array) {
        if(array.length==0)
            return 0;
        int sum = array[0];//保存每组的和
        int maxSum = array[0];//连续子数组最大和
        //动态规划
        for(int i = 1;i<array.length;i++){
            sum = Math.max(sum+array[i],array[i]);
            maxSum = Math.max(sum,maxSum);
        }
        return maxSum;
    }
}
发表于 2018-04-14 15:32:59 回复(0)
使用动态规划。时间复杂度是O(n)。
不光求出最大的子数组之和,还记录了子数组的起始位置。
记录一个子数组对应最大值max_sum,记录数组开始下标begin,记录子数组结束下标end;
记以第i个下标对应的元素为尾的子数组的元素之和的最大值是f(i)。那么对于第i+1个元素,
  1. f(0) = A[0];
  2. 如果f(i)是正数,那么f(i+1) = f(i) + A[i+1];
  3. 如果f(i)是负数,f(i+1) = A[i+1];若f(i) > max_sum,令max_sum = f[i]
也就是f(i) = A[i], i == 0 || f(i-1) <= 0
f(i) = A[i-1] + A[i] i != 0 && f(i-1) > 0 
class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        int max_sum = 0x80000000;
        int length = array.size();
        if(length == 0)return 0;
        int *f = new int[length];
        f[0] = array[0];
        for(int i = 1; i < length; i++){
            if(f[i-1] <= 0){
                f[i] = array[i];   
                if(max_sum < f[i - 1])
                    max_sum = f[i - 1];
            }
            else{
                if(array[i] < 0){
                    if(max_sum < f[i - 1])
                        max_sum = f[i - 1];
                }
                f[i] = f[i-1] + array[i];
            }
        }
        if(max_sum < f[length - 1]){//需要考虑最后一个位置
           max_sum = f[length - 1];
        }  
        return max_sum;
    }
};



编辑于 2015-05-09 09:13:17 回复(3)
可以先给数组排序 在去掉负数,再求
发表于 2017-08-02 20:19:29 回复(0)
# 第一种算法:《算法导论(第四版)--第四章:分治策略 def find_max_subarray(self, A, low, high):  if low == high:  return low, high, A[low]  else:  mid = (low + high) // 2  (left_low, left_high, left_sum) = self.find_max_subarray(A, low, mid)  (right_low, right_high, right_sum) = self.find_max_subarray(A, mid + 1, high)  (mid_low, mid_high, mid_sum) = self.find_max_cross_subarray(A, low, mid, high)   if left_sum > right_sum and left_sum > mid_sum:  return left_low, left_high, left_sum elif right_sum > left_sum and right_sum > mid_sum:  return right_low, right_high, right_sum else:  return mid_low, mid_high, mid_sum #   第二种:非递归方式求最大子数组
def find_max_subarray2(self, A):  max_sum = -sys.maxint
    temp_sum = 0  start_index = 0  end_index = 0  for i in range(len(A)):  if temp_sum < 0:  temp_sum = 0  start_index = i
            end_index = i

        temp_sum += A[i]  if temp_sum > max_sum:  max_sum = temp_sum
            end_index = i return start_index, end_index, max_sum

编辑于 2016-10-05 21:12:46 回复(0)
#include <iostream.h> int maxSum(int* a, int n)  
{ int sum=0; //其实要处理全是负数的情况,很简单,如稍后下面第3点所见,直接把这句改成:"int sum=a[0]"即可 //也可以不改,当全是负数的情况,直接返回0,也不见得不行。  int b=0; for(int i=0; i<n; i++)  
    { if(b<0) //...  b=a[i]; else b+=a[i]; if(sum<b)  
            sum=b;  
    } return sum;  
} int main()  
{ int a[10]={1, -2, 3, 10, -4, 7, 2, -5}; //int a[]={-1,-2,-3,-4}; //测试全是负数的用例  cout<<maxSum(a,8)<<endl; return 0;  
} 

发表于 2016-09-06 20:34:56 回复(0)
求连续子数组的最大和
发表于 2016-09-06 19:57:23 回复(0)
#include <stdio.h>

//复杂度为O(n^2)
int MaxSubseqSum1(int *arr, int n, int* ps, int *pe)
{
    int thisSum = 0, maxSum = 0;
    int i = 0, j = 0;
    *pe = *ps = 0;
    ////记录最大子列下标
    //int s = 0, e = 0;

    for (i = 0; i < n; i++)
    {
        for (j = i; j < n; j++)
        {
            thisSum += arr[j];
            //发现更大的和更新当前结果
            if (thisSum>maxSum)
            {
                //记录下标
                *ps = i;
                *pe = j;
                maxSum = thisSum;
            }
        }
        thisSum = 0;
    }

    return maxSum;
}

//复杂度为O(n)
int MaxSubseqSum2(int *arr, int n, int* ps, int *pe)
{
    int thisSum = 0, maxSum = 0;
    int i = 0;
    *pe = *ps = 0;
    ////记录最大子列下标
    //int s = 0, e = 0;

    for (i = 0; i < n; i++)
    {
        thisSum += arr[i];
        
        //发现更大的和更新当前结果
        if (thisSum > maxSum)
        {
            *pe = i;//记录下标
            maxSum = thisSum;
        }
        else
        {
            if (thisSum < 0)//如果当前子列和为负的
            {
                *ps = i+1;//记录下标
                thisSum = 0;//抛弃
            }
        }
    }

    return maxSum;
}

int main(int argc, char* argv[])
{
    int array[] = {4, -3, 5, -2, -1, 2, 6, -2};
    //int array[] = { -1, 3, -2, 4, -6, 1, 6, -1 };
    int n = sizeof(array) / sizeof(array[0]);

    int s = 0, e = 0;

    //int max = MaxSubseqSum1(array, n);
    int max = MaxSubseqSum2(array, n, &s, &e);

    printf("最大子列和为:%d\n",max);
    printf("子列为:");
    int i = 0;
    for (i = s; i <= e;i++)
    {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}
发表于 2015-04-30 20:15:57 回复(0)
遍历一下,把非负数放到数组,时间复杂度o(n)
发表于 2015-04-30 17:50:20 回复(0)
class Solution {
public:
    int maxSubArray(int A[], int n) {
        if(n <= 0){
            return 0;
        }//if
        // 最大和
        int max = A[0];
        // 当前最大和
        int cur = 0;
        for(int i = 0;i < n;++i){
            // 一旦当前最大和小于0就重置为0,一个负数只能使最大和变小
            if(cur < 0){
                cur = 0;
            }//if
            cur += A[i];
            if(cur > max){
                max = cur;
            }//if
        }//for
        return max;
    }
};

发表于 2015-02-03 09:28:42 回复(2)