第六周 7-1 最大子列和问题

题目

如果我们有这样一个数组sum,sum[i]表示第1个到第i个数的和。快速计算第i个到第j个这个序列的和只要用sum[j] - sum[i-1]就可以了!这样的话,我们就可以省掉最内层的循环,让我们的程序效率更高!时间复杂度比传统的暴力更优,O(n2)

int main()
{
    int k;
    cin >> k;
    //int *p = new int[k];
    vector a(k);
    vector sum(k+1,0);
    for (int i = 0; i < k; i++)
        cin >> a[i];
    for (int i = 1; i <= k; i++)//sum[0]=0,方便计算
        sum[i] = a[i-1] + sum[i - 1];
    int max = sum[0];
    for(int i = 1; i <= k; i++)
        for (int j = i; j <= k; j++)
        {
            int temp = sum[j] - sum[i-1];
            if (temp > max)
                max = temp;
        }
    cout << max << endl;
    //delete[] p;
    system("pause");
    return 0;
}

第二种是利用分治的思想,将问题划分成左中右,然找出左边,右边,跨中间最大的。时间复杂度O(nlogn)

int solve(int left,int right,vector &a)
{
    //序列长度为1时
    if (left == right)
        return a[left];
    //划分成两个更小的子问题
    int mid = (left + right) / 2;
    int lmax = solve(left, mid, a);
    int rmax = solve(mid + 1, right, a);
    //在中间的情况
    int sum = 0, lm = 0, rm = 0;
    for (int i = mid; i >= left; i--)
    {
        sum += a[i];
        if (lm < sum)
            lm = sum;
    }
    sum = 0;
    for (int i = mid+1; i <= right; i++)
    {
        sum += a[i];
        if (rm < sum)
            rm = sum;
    }
    //去三个当中最大的
    int max = rm + lm;
    if (lmax > max)
        max = lmax;
    if (rmax > max)
        max = rmax;
    return max;
}
int main()
{
    int k;
    cin >> k;
    //int *p = new int[k];
    vector a(k);
    for (int i = 0; i < k; i++)
        cin >> a[i];
    int max = solve(0,k-1,a);
    cout << max << endl;
    system("pause");
    return 0;
}

递归的思想,我们用dp[n]表示以第n个数结尾的最大连续子序列的和,于是存在以下递推公式:dp[n] = max(0, dp[n-1]) + num[n],然后取dp[n]中最大的,在代码中直接用原数组保存了dp。时间复杂度O(n)

max(dp[m]) | m∈[1, N]。
int main()
{
    int k;
    cin >> k;
    //int *p = new int[k];
    vector a(k);
    for (int i = 0; i < k; i++)
        cin >> a[i];
    int max = 0;
    if (k == 1)
    {
        if (a[0] < 0)
            max = 0;
    }
    else
    {
        for (int i = 1; i < k; i++)
        {
            if (a[i - 1] > 0)
                a[i] = a[i] + a[i - 1];
            if (a[i] > max)
                max = a[i];
        }
    }
    
    cout << max << endl;
    system("pause");
    return 0;
}

边输入边判断,计算sum,如果和大就保存下来,这是这一块的最大值。如果小于零说明这个不合适,加上的话会让前边的值减小,前边的已经到了最大,接着重新计算下一段最大的sum。

int main()
{
    int k;
    cin >> k;
    //int *p = new int[k];
    vector a(k);
    for (int i = 0; i < k; i++)
        cin >> a[i];
    int sum = 0;
    int max = 0;
    for (int i = 0; i < k; i++)
    {
        sum += a[i];
        if (sum > max)
            max = sum;
        else if (sum < 0)
            sum = 0;
    }
        
    //也可以不用vector,直接输入一个就判断,减小空间复杂度。

    cout << max << endl;
    system("pause");
    return 0;
}

也可以不用vector,直接输入一个就判断,减小空间复杂度。

int main()
{
    int k;
    cin >> k;
    int a;
    int sum = 0;
    int max = 0;
    for (int i = 0; i < k; i++)
    {
        cin >> a;
        sum += a;
        if (sum > max)
            max = sum;
        else if (sum < 0)
            sum = 0;
    }


    //也可以不用vector,直接输入一个就判断,减小空间复杂度。

    cout << max << endl;
    system("pause");
    return 0;
}

你可能感兴趣的:(第六周 7-1 最大子列和问题)