『算法』『数据结构』 浅谈分治算法,理解程序员必懂必会的计算机常见算法——分治算法

基本认识

分治法,字面意思是“分而治之”,就是把一个复杂的一个问题分成两个或多个相同或相似的子问题,再把子问题分成更小的子问题直到最后子问题可以简单地直接求解,原问题的解即子问题的解的合并,这个思想是很多高效算法的基础,例如排序算法(快速排序,归并排序),傅里叶变换(快速傅里叶变换)等。

基本思想与原理

将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
对于一个规模为n的问题,若该问题可以容易的解决(比如规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解决这些子问题,然后将各个子问题的解合并得到原问题的解。

适用的问题

分治算法适用的问题应满足以下几个条件:

(1)该问题的规模缩小到一定程度就可以很容易解决
这个条件非常必要,当问题的数据量也就是规模一定小的时候,问题的复杂度要足够低。

(2)原问题可以分解为多个性质相同的子问题,这里注意是最优子结构性质
这些子问题与原问题相比,只是问题的规模有所降低,其结构和求解方法与原问题相同或相似。

(3)利用该问题分解出的子问题的解可以合并为该问题的解
单单分解为小问题之后还不能算完成,必须要能够将小问题的解合并为这个问题的最终解才能算真正用到了分治的思想。

(4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共子问题
这一条也是最关键的,各个子问题之间必须要保证独立性,即不互相影 响。如果相互之间有影响,这时候我们采用的是动态规划就更加好一点。

求解的步骤与模板

(1)分解
将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题。

(2)处理
若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题。

(3)合并
将各个子问题的解合并为原问题的解。

引例部分

找出伪币问题:
给你一个装有16个硬币的袋子。16个硬币中最多有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。你的任务是找出这个伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。请用尽量少的比较次数来判断伪币的存在并找出这一伪币。

解题思路:
利用分而治之方法,假如把16硬币的例子看成一个大的问题。第一步,把这一问题分成两个小问题。随机选择8个硬币作为第一组称为A组,剩下的8个硬币作为第二组称为B组。这样,就把16个硬币的问题分成两个8硬币的问题来解决。第二步,判断A和B组中是否有伪币。可以利用仪器来比较A组硬币和B组硬币的重量。假如两组硬币重量相等,则可以判断伪币不存在。假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中。接下来,把两个或三个硬币的情况作为不可再分的小问题,在一个小问题中,通过将一个硬币分别与其他两个硬币比较,最多比较两次就可以找到伪币。这样,16硬币的问题就被分为两个8硬币(A组和B组)的问题。通过比较这两组硬币的重量,可以判断伪币是否存在。如果没有伪币,则算法终止。否则,继续划分这两组硬币来寻找伪币。假设B是轻的那一组,因此再把它分成两组,每组有4个硬币。称其中一组为B1,另一组为B2。比较这两组,肯定有一组轻一些。如果B1轻,则伪币在B1中,再将B1又分成两组,每组有两个硬币,称其中一组为B1a,另一组为B1b。比较这两组,可以得到一个较轻的组。由于这个组只有两个硬币,因此不必再细分。比较组中两个硬币的重量,可以立即知道哪一个硬币轻一些。较轻的硬币就是所要找的伪币。

实战部分

最大子序和问题:

在这里插入图片描述

解题思路:
分治法的思路是这样的,连续子序列的最大和主要由这三部分子区间里元素的最大和得到:
第 1 部分:子区间 [left, mid];
第 2 部分:子区间 [mid + 1, right];
第 3 部分:包含子区间 [mid , mid + 1] 的子区间,通过递归的操作,对它们三者求最大值即可。

第一步(分解)
因为最大子序和以领来自于以上三个区间,我们可以将这个大问题分解成三个小的子问题:求左区间最大子序和、求右区间最大子序和、求包含左区间和右区间的子序和。
第二步(处理)
对于左区间和右区间,直接通过递归求单个区间最大子序和即可;求完左区间和右区间后,再求包含左区间和右区间的子序和,不断更新最大值即可。
第三步(合并)
输出最顶层递归函数的返回值即可。

结合下面的图解和代码中的注释很容易明白。

在这里插入图片描述

在这里插入图片描述

下面附上Python3的题解代码

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        l=len(nums)
        if l <= 1:
            return 0 if l==0 else nums[0]
        else:
            #递归计算左半边最大子序和
            max_left = self.maxSubArray(nums[0:l//2])
            #递归计算右半边最大子序和
            max_right = self.maxSubArray(nums[l//2:l])
        
        #计算中间的最大子序和,从右到左计算左边的最大子序和,从左到右计算右边的最大子序和,再相加
        max_l = nums[l//2 -1]
        tmp = 0
        for i in range(l//2 -1,-1,-1):
            tmp += nums[i]
            max_l = max(tmp, max_l)
        max_r = nums[l//2]
        tmp = 0
        for i in range(l//2,l):
            tmp += nums[i]
            max_r = max(tmp, max_r)
        #返回三个中的最大值
        return max(max_right,max_left,max_l+max_r)

趁热打铁 刷题练习部分(持续更新)

以下是LeetCode题库中一些用到分治算法的经典例题的题目及解析,有题干,有题解代码、有解题思路(持续更新):

No.23.合并K个排序链表:
https://www.jianshu.com/p/862bc7144f80

No.53.最大子序和:
https://blog.csdn.net/LanXiu_/article/details/104216342

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容