码迷,mamicode.com
首页 > 编程语言 > 详细

【算法导论】最大子数组问题

时间:2015-01-05 10:59:23      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:

寻找数组A的和最大的非空连续子数组。例如:int A[] = {1, -2, 3, 10, -4, 7, 2, -5}的最大子数组为3, 10, -4, 7, 2,其最大和为18。

 

方法1:枚举所有子数组并求出他们的和。

长度为n的数组有O(n2)个子数组(即:n + n-1 + ... + 1=n(n+1)/2);而且求一个长度为n的数组的和的时间复杂度为O(n)。因此这种思路的时间复杂度是O(n3)

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 
 5 int main(void)
 6 {
 7     vector<int> vtr;
 8     vector<int>::size_type i, j, k;
 9     int tmp, maxSum, lpos, rpos;
10 
11     while (cin >> tmp)
12     {
13         vtr.push_back(tmp);
14     }
15 
16     for (i = 0; i != vtr.size(); i++)
17     {
18         cout << vtr[i] << " ";
19     }
20     cout << endl;
21 
22     maxSum = vtr[0];
23     lpos = 0;
24     rpos = 0;
25     for (i = 0; i != vtr.size(); i++)
26     {
27         for (j = i + 1; j != vtr.size(); j++)
28         {
29             tmp = 0;
30             for (k = i; k <= j; k++)
31             {
32                 tmp += vtr[k];
33             }
34 
35             if (tmp > maxSum)
36             {
37                 maxSum = tmp;
38                 lpos = i;
39                 rpos = j;
40             }
41         }
42     }
43 
44     cout << "maxSum = " << maxSum << endl
45          << "Lpos = " << lpos << endl
46          << "Rpos = " << rpos << endl;
47 
48     return 0;
49 }

 

方法2:当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。

#include <iostream>
#include <vector>
using namespace std;

int FindMaxSubArray(vector<int> &vec, int &lpos, int &rpos)
{
    if (vec.size() == 0)
    {
        return INT_MIN;
    }

    int maxSum = 0, curSum = 0;
    
    for (vector<int>::size_type i = 0; i != vec.size(); i++)
    {
        curSum += vec[i];
        if (curSum < 0)
        {
            curSum = 0;
            lpos = i + 1;
        }
        
        if (curSum > maxSum)
        {
            maxSum = curSum;
            rpos = i;
        }
    }

    if (maxSum == 0)                //数组元素全为非正,最大子数组长度为1
    {
        maxSum = vec[0];
        lpos = 0;
        rpos = 0;

        for (vector<int>::size_type i = 1; i != vec.size(); i++)
        {
            if (vec[i] > maxSum)
            {
                maxSum = vec[i];
                lpos = i;
                rpos = i;
            }
        }
    }
    
    return maxSum;
}

int main(void)
{
    vector<int> vec;
    int tmp, lpos, rpos, maxSum;

    while (cin >> tmp)
    {
        vec.push_back(tmp);
    }

    maxSum = FindMaxSubArray(vec, lpos, rpos);

    cout << "maxSum = " << maxSum << endl
         << "Lpos = "    << lpos      << endl
         << "Rpos = "    << rpos      << endl;
    
    return 0;
}

 

方法3:分治策略。

假定我们要寻找子数组A[low..high]的最大子数组,使用分治法意味着我们要将子数组划分为两个规模尽可能相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后求解两个子数组A[low..mid]和A[mid + 1..high]。所以,A[low..high]的任何连续子数组A[i..j]所处的位置必然是三种情况之一: 

(1)完全位于子数组A[low..mid]中,因此low<=i<=j<=mid;  

(2)完全位于子数组A[mid + 1..high]中,因此mid<=i<=j<=high;

(3)跨越了中点,因此low<=i<=mid<j<=high;

A[low..high]的一个最大子数组必然是完全位于A[low..mid]中、完全位于A[mid + 1..high]中或者跨越中点的所有子数组中和最大者。

  1 #include <iostream>
  2 #include <vector>
  3 using namespace std;
  4 
  5 bool FindMaxCrossingSubArray(const vector<int> &vec, int &low, int mid, int &high, int &crossSum)
  6 {
  7     if (vec.size() == 0)
  8     {
  9         return false;
 10     }
 11 
 12     int leftSum = INT_MIN, rightSum = INT_MIN;
 13     int sum = 0, maxLow, maxHight;
 14     int i;
 15 
 16     for (i = mid; i >= low; i--)
 17     {
 18         sum += vec[i];
 19         if (sum > leftSum)
 20         {
 21             leftSum = sum;
 22             maxLow = i;
 23         }
 24     }
 25 
 26     sum = 0;
 27     for (i = mid + 1; i <= high; i++)
 28     {
 29         sum += vec[i];
 30         if (sum > rightSum)
 31         {
 32             rightSum = sum;
 33             maxHight = i;
 34         }
 35     }
 36 
 37     low = maxLow;
 38     high = maxHight;
 39     crossSum = leftSum + rightSum;
 40     
 41     return true;
 42 }
 43 
 44 bool FindMaximumSubArray(const vector<int> vec, int &low, int &high, int &maxSum)
 45 {
 46     if (vec.size() == 0)
 47     {
 48         return false;
 49     }
 50 
 51     int leftLow, leftHigh;
 52     int rightLow, rightHigh;
 53     int leftSum, rightSum, crossSum;
 54     int midLow, midHigh;
 55     int tmid;
 56     vector<int>::size_type i;
 57 
 58     if (low == high)
 59     {
 60         i = low;
 61         maxSum = vec[i];
 62         return true;
 63     }
 64     else
 65     {
 66         tmid = (low + high) / 2;
 67 
 68         leftLow = low;
 69         leftHigh = tmid;
 70         FindMaximumSubArray(vec, leftLow, leftHigh, leftSum);
 71 
 72         midLow = low;
 73         midHigh = high;
 74         FindMaxCrossingSubArray(vec, midLow, tmid, midHigh, crossSum);
 75 
 76         rightLow = tmid + 1;
 77         rightHigh = high;
 78         FindMaximumSubArray(vec, rightLow, rightHigh, rightSum);
 79 
 80         if (leftSum >= rightSum && leftSum >= crossSum)
 81         {
 82             low = leftLow;
 83             high = leftHigh;
 84             maxSum = leftSum;
 85             return true;
 86         }
 87         else if (rightSum >= leftSum && rightSum >= crossSum)
 88         {
 89             low = rightLow;
 90             high = rightHigh;
 91             maxSum = rightSum;
 92             return true;
 93         }
 94         else
 95         {
 96             low = midLow;
 97             high = midHigh;
 98             maxSum = crossSum;
 99             return true;
100         }
101     }
102 }
103 
104 int main(void)
105 {
106     vector<int> vec;
107     int tmp, maxSum, low, high;
108 
109     while (cin >> tmp)
110     {
111         vec.push_back(tmp);
112     }
113 
114     low = 0;
115     high = vec.size() - 1;
116     FindMaximumSubArray(vec, low, high, maxSum);
117     
118     cout << "Low = " << low << endl
119          << "High = " << high << endl
120          << "maxSum = " << maxSum << endl;
121 
122     return 0;
123 }

 

【算法导论】最大子数组问题

标签:

原文地址:http://www.cnblogs.com/mengwang024/p/4202419.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!