栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

算法与数据结构-分治法

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

算法与数据结构-分治法

分治法 分治法的思想

将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。

分治模式在每层递归时都有三个步骤:

分解(Divide):将原问题分解为若干子问题,这些子问题是原问题的规模较小的实例。解决(Conquer):递归地求解这些子问题。当子问题规模足够小时,可直接求解。合并(Combine):合并子问题的解成原问题的解。 分析分治算法

当一个算法包含对自身的递归调用时,我们往往可以用递归式来描述其运行时间。按照分治模式的三个步骤依次分析。假设 T ( n ) T(n) T(n) 是问题规模为 n n n 的一个问题的运行时间。若问题规模足够小,如对于某个常量 c c c, n ≤ c n le c n≤c,则直接求解需要常量的时间。假设把原问题分解为 a a a 个子问题,每个子问题的规模是原问题的 1 / b 1/b 1/b,则为了求解 a a a 个规模为 n / b n/b n/b 的子问题,我们需要 a T ( n / b ) aT(n/b) aT(n/b) 的时间。设分解的总时间为 D ( n ) D(n) D(n),合并的总时间为 C ( n ) C(n) C(n),则递归式如下:

注意:递归式可以有很多种形式。递归算法可能将问题划分为规模不等的子问题,子问题的规模也并不一定是原问题规模的固定比例(可能每次只比原问题少一个元素)。

分治法的经典例题 归并排序

一个经典的分治法的例子就是归并排序。

最大子数组问题

问题描述:
给定一个整数数组,找到一个具有最大和的连续子数组(最少包含一个元素),返回其最大和。

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

思路分析:
先来假设一下,如果一个数组只有一个值,那么它的最大子数组就是它自己。

nums = [n1]

如果一个数组有两个值呢?我们可以试着将它对半分,那么它的最大子数组必然存在于以下三种情况中:完全属于左半边、完全属于右半边或是跨越左右两边。具体来说,以 nums 为例,它的最大子数组必然是 [n1]、[n2] 或是 [n1, n2] 其中之一。

nums = [n1, n2] 

现在考虑一下更一般的情况,假设这个数组有 n n n 个值,我们同样可以将它对半分。假设从中间 mid 分开,那么它的最大子数组必然属于以下三种情况之一:

    完全属于左半边,即存在于子数组 nums[1..mid] 中。完全属于右半边,即存在于子数组 nums[mid+1..n] 中或是跨越中间值,一部分在左半边,一部分在右半边。
nums[1..n]

因此,我们的想法就是首先分解数组,然后解决子问题,判断最大子数组究竟是三种情况中的哪一种,最后合并子问题的答案以求得原问题的答案。

明显地,如果分解数组后最大子数组完全属于左半边或完全属于右半边,可直接用递归求解。因此我们先来考虑如何处理第三种情况。
// TODO

代码实现 最大子数组问题
#include 
#include 
#include 
using namespace std;


int findMaxCrossingSubArray(vector nums, int low, int mid, int high) {
    // check left part
    int left_sum = INT_MIN; // maximum sum of left part
    int sum = 0; // sum(nums[i..mid])
    for (int i=mid;i>=low;i--) {
        sum += nums[i];
        if (sum > left_sum) {
            left_sum = sum;
        }
    }
    // check right part
    int right_sum = INT_MIN; // maximum usn of right part
    sum = 0; // sum(nums[mid+1..i])
    for (int i=mid+1;i<=high;i++) {
        sum += nums[i];
        if (sum > right_sum) {
            right_sum = sum;
        }
    }
    return left_sum+right_sum;
}


int findMaxSubArray(vector nums, int low, int high) {

    if (low == high) {
        return nums[low];
    }

    int mid = (high-low)/2+low;
    int left_max = findMaxSubArray(nums, low, mid);
    int right_max = findMaxSubArray(nums, mid+1, high);
    int cross_max = findMaxCrossingSubArray(nums, low, mid, high);

    if (left_max>=right_max && left_max>=cross_max) {
        return left_max;
    } else if (right_max>=left_max && right_max>=cross_max) {
        return right_max;
    } else {
        return cross_max;
    }
}

// test
int main(int argc, char const *argv[]) {
    vector nums = {-2,1,-3,4,-1,2,1,-5,4};
    int res = findMaxSubArray(nums, 0, nums.size()-1);
    cout << res << endl;
    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/779209.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号