Task 4.3 求环形数组的最大子数组和

   任务要求:输入一个整形数组,数组里有正数也有负数。

   数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

   如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大。同时返回最大子数组的位置。

   求所有子数组的和的最大值。要求时间复杂度为O(n)

1.设计思想:(假设数组长度为n。)任务要求中提出了数组可以首尾相邻,这样在求数组最大子数组和的时候就要考虑两种情况:一是最大子数组和所在数组在A[0]...A[n]之间,不包括首尾相连的情况;二是最大数组和所在数组在A[i-1]...A[n-1],A[0]...A[j-1]之间就要考虑将A[n-1],A[0]连起来。

这时会有几种不同的思路来解决这个问题:(1)在求子数组和的时候让数组自动循环两遍,在第二次到A[n-1]时停止,可控制子数组长度小于n,这时用之前程序中的循环即可求出环形数组中的最大数组和;

(2)将数组自动地延长一倍,(将{a1,a2,a3....an}扩展成{a1,a2,a3...an,a1,a2,a3,...an}),求新的数组的最大数组和,同时也要将求得的子数组长度控制在n以下;

(3)两种方法的实现类似,但是在实现返回子数组的位置时因为数组的元素位置会有变化所以没有实现。于是改变了思路用对立的一种思路考虑问题:对问题之前提到的两种可能情况分别求最大子数组和,第一种就直接用一个循环可以求得和,勇士可以记录组数组的首尾位置;第二种情况可以先求出数组中的最小子数组和minsum,再用整个数组和减去它求出的就是最大子数组和,同时再记录下最小子数组和数组的首尾位置,换算一下就会得到最大子数组和的数组位置。

2.源代码:

//求数组中连续子数组的最大和(测试后)
//刘子晗   2015/4/12
#include <iostream>
#include <time.h>
using namespace std;

void main()
{
    int i, length, max, sum = 0;
    int head = 0;
    int tail = 0;
    int head1 = 0;
    int tail1 = 0;
    int arr[100];
    srand((unsigned)time(NULL));
    cout << "请输入数组长度:";
    cin >> length;
    for (i = 0; i < length; i++)
    {
        arr[i] = rand() % 20 - 10;
        c7out << arr[i] << "  ";
    }//输出随机产生的数组
    cout << endl;
    int max1 = arr[0];
    int min = arr[0];

    for (i = 0; i < length; i++)
    {
        if (sum <= 0)
        {
            sum = arr[i];
            head = i;
        }
        else
        {
            sum = sum + arr[i];
        }
        if ( sum > max1)
        {
            max1 = sum;
            tail = i;
        }
    }
    cout << "最大子数组和不包括收尾相连的部分时,最大值为:" << max1 << endl;
    
    for (i = 0; i < length; i++)
    {
        if (sum >= 0)
        {
            sum = arr[i];
            head1 = i;
        }
        else
        {
            sum = sum + arr[i];

        }
        if (sum < min)
        {
            min = sum;
            tail1 = i;
        }
    }
    int sum1 = 0;
    for (i = 0; i < length; i++)
    {
        sum1 = sum1 + arr[i];
    }
    int max2 = sum1 - min;
    cout << "最大子数组和包括收尾相连的部分时,最大值为:" << max2 << endl;
    cout << endl;
    if (max1 >= max2)
    {
        cout << "综合两种情况可得最大子数组为:";
        max = max1;
        cout << "arr[" << head + 1 << "]  --  arr[" << tail + 1 << "]" << endl;
        for (int j = head; j <= tail; j++)
        {
            cout << arr[j] << " ";
        }
    }
    else
    {
        max = max2;
        cout << "综合两种情况可得最大子数组为:" ;
        cout << "arr[" << tail1 + 2 << "]  --  arr[" << head1 << "]" << endl;
        for (int j = tail1 + 1; j < length ; j++)
        {
            cout << arr[j] << "  ";
        }

        for (int j = 0; j < head1 ; j++)
        {
            cout << arr[j] << "  ";
        }
    }

    cout << "子数组和的最大值为:" << max;

}    

3.截图:

4.总结:(1)当某一项工程要同时实现件功能时,要对过程采取相应的取舍,某个功能不能实现时,可以改变其他部分的实现方式以实现该功能;

(2)在实现过程中要树立一种从对立面上的角度看问题的思维即逆向思维,这个题目在求第二种的和时,通过求最小和间接得到最大和,就从中巧妙地减少了很大的运算量,是一种很好的方法。

原文地址:https://www.cnblogs.com/mengxiangjialzh/p/4420954.html