zoukankan      html  css  js  c++  java
  • 最大子序列和、最小子序列和、最小正子序列和、最大子序列乘积

    一、先说最大子序列和问题,四种解法,时间复杂度依次递减:

    1、O(N^3)

     1 int MaxSubsequenceSum (const int A[], int N)
     2 {
     3     int ThisSum, MaxSum = 0; 
     4     
     5     for(int i = 0; i != N; ++i)
     6         for(int j = i; j != N; ++j){
     7             ThisSum = 0;
     8             for(int k = i; k != j; ++k)
     9                 ThisSum += A[k];
    10             if(MaxSum < ThisSum)
    11                 MaxSum = ThisSum;
    12         }
    13     return MaxSum;
    14 }

    2、O(N^2)

     1 int MaxSubsequenceSum (const int A[], int N)
     2 {
     3     int ThisSum, MaxSum = 0; 
     4     
     5     for(int i = 0; i != N; ++i){ 
     6         ThisSum = 0;
     7         for(int j = i; j != N; ++j){
     8             ThisSum += A[j];
     9             if(MaxSum < ThisSum)
    10                 MaxSum = ThisSum;
    11         }
    12     }
    13     return MaxSum;
    14 }

    3、O(N*logN)--分治递归--假设N是偶数

     1 int Max3(int a, int b, int c)
     2 {
     3     int max;
     4     max = a > b ? a : b;
     5     max = max > c ? max : c;
     6     
     7     return max; 
     8 }
     9 
    10 static int MaxSubSum (const int A[], int Left, int Right)//Left左边界(0) Right右边界(N-1) 
    11 {
    12     int MaxLeftSum, MaxRightSum;
    13     int MaxLeftBorderSum, MaxRightBorderSum;
    14     int LeftBorderSum, RightBorderSum;
    15     int Mid;
    16     
    17     if(Left == Right)
    18         if(A[Left] > 0)
    19             return A[Left];
    20         else
    21             return 0;
    22     
    23     Mid = (Left + Right) / 2;
    24     MaxLeftSum = MaxSubSum(A, Left, Mid);      //左侧递归
    25     MaxRightSum = MaxSubSum(A, Mid+1, Right);  //右侧递归 
    26     
    27     MaxLeftBorderSum = 0; LeftBorderSum = 0;   //相比于第二种算法,去掉一个循环,每次分一半来求解最大值 
    28     for(int i = Mid; i != Left-1; --i){
    29         LeftBorderSum += A[i];
    30         if(LeftBorderSum > MaxLeftBorderSum)
    31             MaxLeftBorderSum = LeftBorderSum;
    32     }
    33     
    34     MaxRightBorderSum = 0; RightBorderSum = 0;
    35     for(int i = Mid+1; i != Right+1; ++i){
    36         RightBorderSum += A[i];
    37         if(RightBorderSum > MaxRightBorderSum)
    38             MaxRightBorderSum = RightBorderSum;
    39     }
    40     
    41     return Max3(RightBorderSum, MaxRightSum,        // 比较左侧最大值,右侧最大值和左右相加最大值 
    42             MaxLeftBorderSum+MaxRightBorderSum);
    43 }

    4、O(N)

     1 int MaxSubsequenceSum (const int A[], int N)
     2 {
     3     int ThisSum, MaxSum;
     4     ThisSum = MaxSum = 0; 
     5     
     6     for(int i = 0; i != N; ++i){ 
     7         ThisSum += A[i];
     8         if(MaxSum < ThisSum)
     9             MaxSum = ThisSum;
    10         else if(ThisSum < 0)
    11             ThisSum = 0;
    12     }
    13     return MaxSum;
    14 }

       该算法附带的一个优点是,它只对数据进行一次扫描,一旦A[i]被读入并处理,它就不再需要被记忆。不仅如此,在任何时刻,算法都能对它已经读入的数据给出子序列问题的正确答案。具有这种特性的算法叫联机(online)算法。仅需要常量空间并以线性时间运行的联机算法几乎是完美的算法。

    二、最小子序列和O(N)

        只是改变判断条件符号的方向。

     1 int MaxSubsequenceSum (const int A[], int N)
     2 {
     3     int ThisSum, MaxSum;
     4     ThisSum = MaxSum = 0; 
     5     
     6     for(int i = 0; i != N; ++i){ 
     7         ThisSum += A[i];
     8         if(MaxSum > ThisSum)
     9             MaxSum = ThisSum;
    10         else if(ThisSum > 0)
    11             ThisSum = 0;
    12     }
    13     return MaxSum;
    14 }

     三、最小正子序列和

    感谢@windrang指出我的错误。

    1、O(N^2)

    for (int i = 0; i != N; ++i) {
        ThisSum = 0;
        for (int j = i; j != N; ++j) {
            ThisSum += A[j];
            if (MinSum > ThisSum && ThisSum > 0)
                MinSum = ThisSum;
        }
    }

    2、O(NlogN)

    #include <iostream>
    #include <algorithm>
    #include <string.h>
    
    struct Item {
        int value;
        int index;
    };
    
    bool cmp(Item& a, Item& b) 
    { 
        if (a.value == b.value) {
            a.index = b.index = a.index < b.index ? a.index : b.index;
        }
        return a.value < b.value;
    }
    
    int MinSubsequenceSum (const int A[], int N)
    {
        int ThisSum = 0, MinSum = 0;
        Item* B = new item[N];
        
        memset(B, 0, sizeof(Item) * N);
        
        for (int i = 0; i < N; ++i) {
            B[i].index = i;
            ThisSum += A[i];
            B[i].value = ThisSum;
        }
        std::sort(B, B+N, cmp);
        
        MinSum = B[0].value > 0 ? B[0].value : 2<<29;
        
        for (int i = 1; i < N; ++i) {
            if ((B[i-1].index < B[i].index) && (B[i].value - B[i-1].value > 0) && (B[i].value - B[i-1].value < MinSum)) {
                MinSum =  B[i].value - B[i-1].value;
            }
        }
        delete[] B;
        return MinSum;
    }
    int main ()
    {
        int A[8] = {4,-1,6,-2,-1,3,6,-2}; //  4,  0, 4,  1,  -1
        std::cout << MinSubsequenceSum(A, 8);
        return 0;
    }

    这里是是根据绿色夹克衫老爷的答案来写的。其中需要注意的是排序,在判断函数中,需要将相同元素值的序列合并为较小的序列。否则的话,序列(4, 0, 4, 1, -1),得出的答案为4。

    四、最大子序列乘积

    DP

    思路:
    以元素i结尾序列提供的最大正数记做 pos, 最小负数记做 nag
    a[n] 大于零时:
        pos[n] = max{pos[n-1] * a[n], a[n]}
        max_value = max{max_value, pos[n]}
        若n-1位置存在最小负数, 更新 nag[n] = nag[n-1] * a[n]
    a[n] 小于零时:
        pos[n] = max{nag[n-1] * a[n], 0.0}
        max_value = max{max_value, pos[n]}
        更新 nag[n] = min{pos[n-1] * a[n], a[n]}
    a[n] 等于零时:
        清空 nag[n] 与 pos[n]

    代码,

    #include <iostream>
    
    inline double max(const double& a, const double& b)
    {
    return (a > b) ? a : b; } double MaxSubsequenceProduct(double a[], int len) { double Max = 0.0, pos = 0.0, old = 0.0, nag = 1.0; for (int i = 0; i < len; ++i) { if (a[i] > 1e-6) { pos = max(old * a[i], a[i]); Max = max(Max, pos); if (nag < -1e-6) { nag *= a[i]; } } else if (a[i] < -1e-6) { pos = max(0.0, nag * a[i]); Max = max(Max, pos); nag = (old * a[i] > a[i]) ? a[i] : old * a[i]; } else { nag = 1.0; pos = 0.0; } old = pos; } return Max; } int main() { double a[7] = { -2.5, 4, 0, 3, 0.5, 8, -1 }; std::cout << MaxSubsequenceProduct(a, 7); std::cin >> a[2]; return 0; }

    出处来自木叶漂舟

  • 相关阅读:
    Spring核心概念
    机器学习第二次作业
    机器学习第一次作业
    软工实践个人总结
    第04组 Beta版本演示
    第04组 Beta冲刺(5/5)
    第04组 Beta冲刺(4/5)
    第04组 Beta冲刺(3/5)
    第04组 Beta冲刺(2/5)
    第04组 Beta冲刺(1/5)
  • 原文地址:https://www.cnblogs.com/clairvoyant/p/4944737.html
Copyright © 2011-2022 走看看