分治法一个整数数列求最大值最小值_从生活出发了解什么是分治算法

10ecc20f5e5a6b92660224d0298aa77c.png

Divide And Conquer 分治法

假如一个目标很难达成的话,不如就把它分成若干的小目标吧...

一天小明去超市买了一袋零食,粗心的售货员没有将其中的一件商品消磁,这时如何才能比较有效率的断定 哪一件零食才是没有消磁的零食呢?

二分查找

一个很好的办法就是,取这带零食的一半过检验机,将发出警报的这一半继续分一半过机。这样,每一次的数量都会是 上一次的一半,最终可以确定到底是哪一个商品。比较起来一件件过机,效率大大的提高了。

以上的这个故事讲述的就是,我们分治法的一种特殊情况,二分查找。在计算机上,遍历查找的时间复杂度是O(n), 但二分查找的时间复杂度仅仅是 O(log2(n)),常常被用于树状结构查找。

分治法

分治法的核心思想就是,将原问题分解成小问题来求解,那么这类问题必须满足一下几个条件:

  • 原问题可以被分解成性质类似的子问题
  • 问题规模缩小后有利于得出结果
  • 子问题的解能够协助原问题得到最终解
  • 子问题互相独立,不存在依赖关系

下面,我们就举一个分治法的经典例子。

归并排序(merge-sort)

我们现在有一组数需要进行排序:

  • [5,8,4,2,1,6,7,3]

把它分解成若干个小数组进行对比:

  • [5,8,4,2] [1,6,7,3]
  • [5,8] [4,2] [1,6] [7,3]

通过算法合并有序子序列就依次变成了:

  • [5,8] [2,4] [1,6] [3,7]
  • [2,4,5,8] [1,3,6,7]
  • [1,2,3,4,5,6,7,8]

这就是归并排序核心思想,把排序问题变成了排序子序列然后合并有序子序列这个小问题了。

那么如何合并子序列?

方法很简单。就是平时双指针的方式,就以[2,4,5,8] [1,3,6,7] 举例:

  • 设置两个指针(i = 0,j = 0)分别为与开头 [2,4,5,8] [1,3,6,7]
  • 因为 1 < 2 取 1 ,j 向后推一位 (i = 0,j = 1)[2,4,5,8] [1,3,6,7]
  • 又因为 2 < 3 取 2,i 向后推一位 (i = 1,j = 1) [2,4,5,8] [1,3,6,7]
  • ...

按指针位置两两对比,最终实现排序。

JavaScript 详细代码:

const 

排序以上数组,一一对比需要(8 * 7 / 2)28 次,时间复杂度为 O(n^2) 而归并排序只需要对比 16 次,每次合并操作的时间复杂度为O(n), 排序时间O(log2n), 一共的时间复杂度就是O(nlogn)。并且,比起一些排序算法来说,效率稳定。

最大子序和 (maximum-subarray)

这是一道 LeetCode 的题目: Jump link

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

例如:

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

这个问题也可以使用分治法解决:

function 

总结

尽管我知道目标,但是如果我只看接下来的这一步, 我就能够避开恐慌和昏头转向。—— 莫顿·亨特 《走一步,再走一步》

既然已经明白了什么是分治法,接下来不如就去看看和分治法异曲同工的动态规划吧。

https://github.com/NoisyWinds/algorithms-store/blob/master/JavaScript/Divide-And-Conquer/README.md​github.com
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值