算法设计与分析第二章作业——以求解最大子段和为例谈谈分治算法

一、用分治法的思想解题

分治法的基本思想:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。

题目:给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。

e.g.

输入:-2 11 -4 13 -5 -2 

输出:20

最大子段和为:11 -4 13

这个问题该如何用分治算法来求解呢?

1、首先分解,划分问题:

将问题规模为n的问题分解为两个问题规模为n /2的问题

2、递归求解两个子问题

3、求解子问题

理解:该问题存在三种情况:

1.最大子段和于[0, 2 / n]区域内

2.最大子段和于[2 / n + 1, n]区域内

3.最大子段和的起点于[0, 2 / n]区域内,终点于[2 / n + 1, n]区域内

ret_left 为第一种情况,ret_right为第二种情况,下面两个for计算第三种情况,最后比较究竟哪种情况的子段和最大,返回最大子段和

函数伪代码如下:

// 求解最大子段和的函数,返回值为最大子段和
int SubArraySum(int* a, int l, int r) {  // 数组a的起始下标为l,末尾下标为r
    if(l == r) return a[l] < 0 ? 0 : a[l];  // 仅有一个数,不用再分解了,返回,由于没有m-1,故不存在l>r,l == r即可,l >= r也可以
    mid = l + (r - l) / 2;  // 相当于(l + r) / 2 
    ret_left = SubArraySum(a, l, m);  // 返回[l, m]区域内的最大子段和
    ret_right = SubArraySum(a, m+1, r);  // 返回[m+1, r]区域内的最大子段和
    
    
    //  计算起点于[l, m],终点于[m+1, r]的最大子段和
    sum = 0;
    left_max = 0; 
    for(i = m; i >= l; i--) {  // 计算[l, m]的最大子段和,从a[m]开始向左移动
        sum += a[i];
        if(sum > left_max)
            left_max = sum;
    }

    sum = 0;
    right_max = 0; 
    for(i = m+1; i <= r; i++) {  // 计算[m+1, r]的最大子段和,从a[m+1]开始向右移动
        sum += a[i];
        if(sum > right_max)
            right_max = sum;
    }

    ret = left_max + right_max;  // 起点于[l, m],终点于[m+1, r]的最大子段和是多少
    // 三种情况做比较,返回子段和最大的
    if(ret_left > ret)
        ret = ret_left;
    if(ret_rigth > ret)
        ret = ret_right;
    return ret;
}

二、根据主定理求解时间:

分解问题:T(n) = O(1)

递归求解各子问题:将问题规模为n的问题分解为两个问题规模为n /2的问题, T(n) = 2T(n / 2) 

求解子问题:两个for循环,范围相加为n,T(n) = O(n)

综上时间复杂度:T(n) = O(1) + 2T(n / 2) + O(n) = O(nlogn)

三、通过第二章的学习,我对分治法的体会和思考

运用分治法的思想可以巧妙改变求解问题的规模,进而减小时间复杂度,提高程序的运行效率,将问题规模由最初的n分解为更小的子问题来求解,很巧妙的方法使得时间复杂度有所减小。我发现分治法重点放在不同环节会产生不同的算法,如归并排序将重点放在合并这个步骤,简单分解为两个部分,那么时间主要就是耗费在合并的环节;快速排序将重点放在分的部分,将数放入合适的位置来将数组分为两部分,那么时间主要就是耗费在分的环节。同时根据合并排序与快速排序的侧重点不同,各自又有不同的应用,像归并排序可用于求逆序对数目,于合并处做修改,而快排可用于找第k小的元素,利用分的结果。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值