【数组】最大子数组问题(要求时间复杂度最佳)

思路:

就是最大子列和呗,时间复杂度最佳那就是O(n),使用贪心算法。

以下是三种方法,时间复杂度递减

  1 // preface.cpp : 基本概念 求最大子列和
  2 #include "pch.h"
  3 #include <iostream>
  4 using namespace std;
  5 
  6 /* 方法一:确定子列的首部,逐个累加,时间复杂度 O(n^2)*/
  7 int MaxSubseqSum1(int n, int a[]) {
  8     int max = 0;
  9     for (int i = 0; i < n; i++) {
 10         int temp = 0;//当前子列和
 11         for (int j = i; j < n; j++) {
 12             temp += a[j];
 13             if (temp > max)
 14                 max = temp;
 15         }
 16     }
 17     return max;
 18 }
 19 
 20 /* 方法二:分治法,递归分成两份,分别求每个分割后最大子列和,时间复杂度为 O(n*logn)*/
 21 
 22 
 23 /*返回三者中的最大值*/
 24 int Max3(int A, int B, int C) {
 25     return (A > B) ? (A > C ? A : C) : (B > C ? B : C);
 26 }
 27 
 28 /*分治*/
 29 int DivideAndConquer(int a[], int left, int right) {
 30     /*递归结束条件:子列只有一个数字*/
 31     // 当该数为正数时,最大子列和为其本身
 32     // 当该数为负数时,最大子列和为 0
 33     if (left == right) {
 34         if (a[left] > 0)
 35             return a[left];
 36         return 0;
 37     }
 38 
 39     /* 分别递归找到左右最大子列和*/
 40     int center = (left + right) / 2;
 41     int MaxLeftSum = DivideAndConquer(a, left, center);
 42     int MaxRightSum = DivideAndConquer(a, center+1, right);
 43 
 44     /* 再分别找左右跨界最大子列和*/
 45     int MaxLeftBorderSum = 0;
 46     int LeftBorderSum = 0;
 47     for (int i = center; i >= left; i--) {//从边界出发向左找
 48         LeftBorderSum += a[i];
 49         if (MaxLeftBorderSum < LeftBorderSum)
 50             MaxLeftBorderSum = LeftBorderSum;
 51     }
 52     int MaXRightBorderSum = 0;
 53     int RightBorderSum = 0;
 54     for (int i = center + 1; i <= right; i++) {  // 从边界出发向右边找
 55         RightBorderSum += a[i];
 56         if (MaXRightBorderSum < RightBorderSum)
 57             MaXRightBorderSum = RightBorderSum;
 58     }
 59     /*最后返回分解的左边最大子列和,右边最大子列和,和跨界最大子列和三者中最大的数*/
 60     return Max3(MaxLeftSum, MaxRightSum, MaXRightBorderSum + MaxLeftBorderSum);
 61 }
 62 
 63 int MaxSubseqSum2(int n, int a[]) {
 64     return DivideAndConquer(a, 0, n - 1);
 65 }
 66 /*“贪心法”,即不从整体最优上加以考虑,只做出某种意义上的局部最优解。
 67 其实最大子列和与它的首部和尾部都没有关系,我们只关心它当前的大小。
 68 当临时和加上当前值为负时,它对之后子列和肯定没有帮助(甚至只会让之后的和更小!)
 69 我们抛弃这段临时和将它置0*/
 70 
 71 /* 方法三:直接累加,如果累加到当前的和为负数,置当前值或0,时间复杂度为 O(n)*/
 72 int MaxSubseqSum3(int n, int a[]) {
 73     int max = 0;
 74     int tempmax = 0;
 75     for (int i = 0; i < n; i++) {
 76         tempmax += a[i];
 77         if (tempmax < 0) {
 78             tempmax = 0;
 79         }
 80         else if (max < tempmax) {
 81             max = tempmax;
 82         }
 83         
 84     }
 85     return max;
 86 }
 87 
 88 int main()
 89 {
 90     int n;
 91     int a[100000 + 5];
 92     cin >> n;
 93     for (int i = 0; i < n; i++)
 94         cin >> a[i];
 95     MaxSubseqSum1(n, a);
 96     MaxSubseqSum2(n, a);
 97     MaxSubseqSum3(n, a);
 98     cout<< MaxSubseqSum1(n, a)<<endl;
 99     cout << MaxSubseqSum2(n, a)<<endl;
100     cout << MaxSubseqSum3(n, a)<<endl;
101     return 0;
102 }

 

posted @ 2020-04-07 17:22  PennyXia  阅读(529)  评论(0编辑  收藏  举报