最大子数组问题 时间复杂度为Θ(n)

时间:2022-07-07 16:49:40

《算法导论》中提出的一个解题思路,从数组的左边界开始,由左至右处理,记录到目前为止已经处理过的最大子数组。若已知A[1..j]的最大子数组基于如下性质将解扩展为A[1..j+1]的最大子数组:A[1..j+1]的最大子数组要么是A[1..j]的最大子数组,要么是某个子数组A[i..j+1](1≤i≤j+1)。在已知A[1..j]的最大子数组的情况下,可以在线性时间内找出形如A[i..j+1]的最大子数组。该算法的时间复杂度为因此该算法的时间复杂度为Θ(n)

#include <stdio.h>  
#include <string.h>  
 
struct subarray { 
    int start; 
    int end; 
    int sum; 
}; 
 
 #define max(__x, __y) ((__x) > (__y) ? (__x) : (__y))  
  
 static void max_sumarray(int *a, int len, void *p) 
 { 
     struct subarray *sa = (typeof(sa))p; 
     int i; 
     int max_sum, prev, tmp; 
     int start, end; 
      
     if (!sa || (len <= 0)) { 
         fprintf(stderr, "Invalid argument.\n"); 
         return; 
     } 
      
     memset(sa, 0, sizeof(*sa)); 
      
     max_sum = a[0]; 
     prev = a[0]; 
     start = end = 0; 
     for (i = 1; i < len; ++i) { 
         prev = max(a[i], prev + a[i]);   //寻找以当前位置为结尾的最大子串
           
         if (prev < max_sum) { 

    /**

    **如果以当前位置为结尾的最大子串是其本身,则下次扫描时以当前位置为结尾的最大子串的起始位置为本位置

    **/ 
             if (prev == a[i]) { 
                 start = i; 
             } 
             continue; 
         } 
          
         max_sum = prev; 
          
         if (prev == a[i]) { 
             sa->start = sa->end = i; 
         } else { 
             sa->start = start; 
             sa->end = i; 
         } 
     } 
      
     sa->sum = max_sum; 
 } 
  
 int main(void) 
 { 
     int source[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5,  -22, 15, -4, 7}; 
     struct subarray sa; 
      
     max_sumarray(source, sizeof(source) / sizeof(source[0]), &sa); 
     printf("Max sum: %d, start: %d, end: %d.\n", sa.sum, sa.start, sa.end); 
     return 0; 
 }