递归算法求解最大子数组问题---纯C语言

 题目:已知整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和以及子数组的区间,

示例:

输入:nums = [13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]

输出:(7,10,43)

解释:最大子数组为[18,20,-7,12],索引为nums[7]~nums[10],和为43

分治思想:

任何连续子数组nums[i...j]一定是一下三种情况之一:

  • 完全位于子数组nums[low,mid]
  • 完全位于子数组nums[mid+1,high]
  • 跨越了中间点mid,既i<=mid<j

第一步,先解决跨越中间点mid的情况

FIND_MAX_CROSSING_SUBARRAY(A,low,mid,high):

  1. left_sum = -\infty
  2. sum = 0
  3. for i  = mid  downto low
  4.       sum = sum + A[i]
  5.        if sum > left_sum
  6.             left_sum = sum
  7.             max_left = i
  8. right_sum = -\infty
  9. sum = 0
  10. for j  = mid+1  to high
  11.       sum = sum + A[j]
  12.        if sum > right_sum
  13.             right_sum = sum
  14.             max_left = j
  15. return (max_left,max_right,left_sum + right_sum)

第二步,构造递归函数

FIND_MAX_SUBARRAY(A,low,high):

  1. if high == low
  2.     return (low,right,A[low])
  3. else
  4.      mid = (low + high) / 2
  5.      (left_low,left_high,left_sum) = FIND_MAX_SUBARRAY(A,low,mid)
  6.      (right_low,right_high,right_sum) = FIND_MAX_SUBARRAY(A,mid+1,high)
  7.      (cross_low,cross_high,cross_sum) = FIND_MAX_CROSSING_SUBARRAY(A,low,mid,high)
  8.      if(left_sum >= right_sum && left_sum >= cross_sum)
  9.           return(left_low,left_high,left_sum)
  10.      else if((right_sum >= left_sum&& right_sum >= cross_sum)
  11.           return (right_low,right_high,right_sum)
  12.      else
  13.           return (cross_low,cross_high,cross_sum)
#include<stdio.h>
#include<stdlib.h>

#define N 16
typedef struct _Node
{
    int left;
    int right;
    int sum;
}Node;//返回的数据类型
int Diff[N] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int main() //ZCR: fighting
{
    Node* Find_Max_Crossing_Subarray(int* A,int low,int mid,int high);//函数声明,必须,因为函数的定义在main函数下方
    Node* Find_Max_Subarray(int* A,int low,int high);//函数声明
    Node* ptr;//定义指针接受递归结束返回的最大子数组的左索引,右索引 以及 和
    ptr = Find_Max_Subarray(Diff,0,15);
    if(!prt)
    {
        printf("动态内存申请失败!!");
        return 0;
    }
    printf("(%d,%d,%d)",ptr->left,ptr->right,ptr->sum);
    free(ptr);//函数内部用了malloc,一定要释放内存,不然会造成内存泄漏
    ptr = NULL;//良好编程习惯,别让它成为野指针,指向NULL就不是野指针的
    return 0;
}

Node* Find_Max_Crossing_Subarray(int* A,int low,int mid,int high)
{
    int left_sum = -100000, right_sum = -100000;
    int i,max_left,max_right;
    Node* s = (Node*)malloc(sizeof(Node));
    if(!s)
    {
        printf("动态内存申请失败!!");
        return NULL; //申请动态内存失败,直接返回
    }
    int temp = 0;
    for(i = mid;i >= low;i--)
    {
        temp += A[i];
        if(temp > left_sum)
        {
            left_sum = temp;
            max_left = i;
        }
    }
    temp = 0;
    for(i = mid + 1;i <= high;i++)
    {
        temp += A[i];
        if(temp > right_sum)
        {
            right_sum = temp;
            max_right = i;
        }
    }
    s->left = max_left;
    s->right = max_right;
    s->sum = left_sum + right_sum;
    return s;
}

Node* Find_Max_Subarray(int* A,int low,int high)
{
    Node *l,*r,*c,*d;//l=left,r=right,c=cross,d=done
    int mid;
    if(low == high)
    {
        d = (Node*)malloc(sizeof(Node));
        if(!d)
        {
            printf("动态内存申请失败!!");
            return NULL;
        }
        d->left = low;
        d->right = high;
        d->sum = A[low];
        return d;
    }
    else
    {
        mid = (low + high) / 2;
        l = Find_Max_Subarray(A,low,mid);
        r = Find_Max_Subarray(A,mid+1,high);
        c = Find_Max_Crossing_Subarray(A,low,mid,high);
        if((l->sum >= r->sum) && (l->sum >= c->sum))
        {
            free(r);r = NULL;
            free(c);c = NULL;
            return l;
        }
        else if((c->sum >= l->sum) && (c->sum >= r->sum))
        {
            free(l);l = NULL;
            free(r);r = NULL;
            return c;
        }
        else
        {
            free(l);l = NULL;
            free(c);c = NULL;
            return r;
        }
    }
    
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值