最大子数组问题(C语言)

什么是最大子数组问题呢?

给出一列数组,

假设张三有超能力,能预测股票走向

该数组为一个股票的价格走向;第一行是日期,第二行为该日期股票的大盘价格

求这16天哪一天买入,哪一天卖出,赚的最多?

本问题在这里学习两种解法:

第一种是暴力算法

       把所有的组合一一列出并且求出大小进行存储,然后比较选出最大的,即可解的答案。

       从这个不难分析得出,假设有n天,其有(2的n次方)种组合

其时间复杂度为O(n²)。

因此我们要对其进行优化,采用分治的思路进行设计:

第二种方法:

       我们把子数组分布分析一下:

       假设首元素为low ,顶元素为high,中间为mid;

       假设有一中心点,子数组可能分布的情况为三种:

  1. 全部在左边 A (low , mid)(low≤ i ≤ j ≤high)
  2. 全部在右边A( mid + 1 , high) (mid < i ≤ j ≤high)
  3. 跨越中心点 (low ≤ i ≤ mid < j ≤high)

如图

所以我们可以写出策略:

先定义一个结构体:

typedef struct {

       int low,high,sum;

}part;

代码实现如下:

int mid;

              mid = (low+high)/2;

              p = find_maximum_subarray(a,low,mid);

              left_low = p.low;

              left_high = p.high;

              left_sum = p.sum;

              p = find_maximum_subarray(a,mid+1,high);

              right_low = p.low;

              right_high = p.high;

              right_sum = p.sum;

              p = find_crossing_subarray(a,low,mid,high);

              cross_low = p.low;

              cross_high = p.high;

              cross_sum = p.sum;

这个代码的流程就是将数组不断的平分然后分成一个个小的“中点”

然后对这些“中点”进行跨中点的比较

代码实现如下:

part find_crossing_subarray(int a[],int low,int mid,int high){

       part p;

       int i,j;

       int right_sum;

       int max_left,max_right;

       int left_sum = -1000;  //此处为负无穷,要小于所有的值,才能作为初始值比较

       int sum = 0;

       for(i = mid;i>=low;i--){       //从中点到最左侧依次递减

              sum += a[i];

              if(sum>left_sum){

                     left_sum = sum;

                     max_left = i;

              }

       }

       sum = 0;

       for(j = mid+1;j<=high;j++){

              sum += a[j];

              if(sum>right_sum){

                     right_sum = sum;

                     max_right = j;

              }

       }

       p.high = max_right;

       p.low = max_left;

       p.sum = right_sum + left_sum;

       return p;

}

然后进行左侧、右侧、跨中点三个值的比较,返回最大值      

if(left_sum>=right_sum&&left_sum>=cross_sum){

                     p.low = left_low;

                     p.high = left_high;

                     p.sum = left_sum;

                     return p;

              }

              else if(right_sum>=left_sum&&right_sum>=cross_sum){

                     p.high = right_high;

                     p.low = right_low;

                     p.sum = right_sum;

                     return p;

              }

              else{

                     p.high = cross_high;

                     p.low = cross_low;

                     p.sum = cross_sum;

                     return p;

              }

完整代码实现如下:

#include <stdio.h>

#include <stdlib.h>



typedef struct {

       int low,high,sum;

}part;





part find_crossing_subarray(int a[],int low,int mid,int high){

       part p;

       int i,j;

       int right_sum;

       int max_left,max_right;

       int left_sum = -1000;  //此处为负无穷,要小于所有的值,才能作为初始值比较

       int sum = 0;

       for(i = mid;i>=low;i--){       //从中点到最左侧依次递减

              sum += a[i];

              if(sum>left_sum){

                     left_sum = sum;

                     max_left = i;

              }

       }

       sum = 0;

       for(j = mid+1;j<=high;j++){

              sum += a[j];

              if(sum>right_sum){

                     right_sum = sum;

                     max_right = j;

              }

       }

       p.high = max_right;

       p.low = max_left;

       p.sum = right_sum + left_sum;

       return p;

}



part find_maximum_subarray(int a[],int low,int high){

       part p;

       int left_high,left_low,left_sum;

       int right_low,right_high,right_sum;

       int cross_low,cross_high,cross_sum;

       if(high==low){

              p.low = low;

              p.high = high;

              p.sum = a[low];

              return p;

       }

       else{

              int mid;

              mid = (low+high)/2;

              p = find_maximum_subarray(a,low,mid);

              left_low = p.low;

              left_high = p.high;

              left_sum = p.sum;

              p = find_maximum_subarray(a,mid+1,high);

              right_low = p.low;

              right_high = p.high;

              right_sum = p.sum;

              p = find_crossing_subarray(a,low,mid,high);

              cross_low = p.low;

              cross_high = p.high;

              cross_sum = p.sum;

             

              if(left_sum>=right_sum&&left_sum>=cross_sum){

                     p.low = left_low;

                     p.high = left_high;

                     p.sum = left_sum;

                     return p;

              }

              else if(right_sum>=left_sum&&right_sum>=cross_sum){

                     p.high = right_high;

                     p.low = right_low;

                     p.sum = right_sum;

                     return p;

              }

              else{

                     p.high = cross_high;

                     p.low = cross_low;

                     p.sum = cross_sum;

                     return p;

              }

       }

}



int main(){

       int a[16] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};

       part p;

       p = find_maximum_subarray(a,0,15);

       printf("%d,%d,%d",p.low+1,p.high+1,p.sum);

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值