用二分法优化动态规划——实现快速决策

本文介绍了如何使用二分法优化动态规划解决导弹拦截系统问题,即寻找最长不下降子序列的长度。通过分析问题本质,得出所有位置都可能成为答案结尾的结论,进而构建动态规划的转移方程。通过维护有序数组并运用二分查找,将算法复杂度优化至NlogN。文章鼓励读者理解优化背后的推导过程,以应对类似问题。
摘要由CSDN通过智能技术生成

本文始发于个人公众号:TechFlow,原创不易,求个关注


今天是算法与数据结构专题的17篇文章,也是动态规划专题的第6篇。

今天我们一起来看一道非常经典的动态规划的问题,有多经典呢?我想了一下,大概是我这辈子做的最早的一道动态规划问题,以至于我现在都记得它的题面。

题面

这道题就是导弹拦截系统,说是某一个国家开发了一套导弹拦截系统,这个拦截系统可以拦截敌国打来的导弹。不同射程的导弹在弹射出去的时候的飞行高度都不同,这个拦截系统可以从低到高拦截飞来的导弹,但是它下一次拦截的高度必须大于等于上一次高度,只能升高不能降低。那么请问,假设我们检测到了所有敌国发射的导弹飞行的高度,请问我们最多可以拦截其中多少枚?

上面讲题意讲了这么多,其实用一句话就概括了,就是求一个序列当中最长不下降子序列的长度。也有题目反过来求最长不上升子序列,意思是一样的。

暴力解法

我们来看一个例子,假设敌国一共发来了8枚导弹,它们的飞行高度分别是:[65, 158, 170, 299, 300, 155, 207, 389]。

我们用眼睛看看还是蛮容易找出答案的,答案应该是[65, 158, 170, 299, 300, 389]一共6枚导弹,其中的155和207无法拦截。假设我们不知道这是一个动态规划算法,我们怎么想出解法呢?

还是老规矩,我们先从最简单的暴力方法开始思考。最暴力的方法就是枚举这n个数所有可能出现的状态,对于其中的每个元素而言,都有两种状态,一种是拿取,一种是不拿。那么对于一个n个元素的数组而言,显然一共会有 2 n 2^n 2n个不同的可能。然后我们再依次判断每一种可能性是否合法,保留合法的长度最大的那一个。

当然我们也可以用搜索来做,我们可以在搜索的过程当中排除掉非法的组合,但在极端情况下,比如整个数组升序的时候,那么还是会枚举到所有的情况,那么整体的复杂度依然是 2 n 2^n 2n。这显然是我们不能接受的。

那我们怎么来找到更好的解法呢?

感性的认识

我们观察和思考一下这个问题,我们会发现在这个问题当中,不同规模的解法应该都是一样的。如果某种方法可以解出长度为1000的序列,那么自然也可以解出长度为5的序列,反之也是一样。所以我们不由地可以想到,那我们从最简单的情况开始入手,能不能找到解法呢?

我们从长度为1的数组开始,显然答案是确定的,就是1.

如果长度是2呢?比如[65, 158],那么我们需要判断一下第二个数能否跟在第一个数后面,也就是说第二个数是否大于等于第一个数,如果成立的话,那答案就是2,否则答案还是1,比如[65, 34],最长的序列就只能是[65]或者[34]。

那如果是3个数呢?情况会复杂一点,我们可以反过来分析,如果答案是3,那么只有一种情况就是序列是递增的,如果答案是2,那么就有两种情况,一种是前面两个元素构成递增比如[20, 30, 10],第二种情况是前面两个元素之中的一个和第三个数构成递增,比如[10, 5, 30]或者是[10, 5, 8]。也有可能答案是1,当序列是递减的时候。

表面上看我们什么也没有发现,并没有找出一个好的方案来解决问题,但是其实已经有一个很重要的结论摆在了我们面前——这个最长不下降的序列并不一定包含最后一个元素

看起来这似乎是废话,答案当然可能不包含最后一个元素,因为如果最后一个元素非常小,它显然不可能组成很长的序列。但是反过来看,我们的结论会整个颠覆。既然答案并不一定以最后一个元素结尾,而序列必须有一个结尾,而目前我们没有结论证明某一个节点会不能作为结尾。所以我们自然地得出结论,所有位置都有可能是答案的结尾

这个其实很好证明,我们来看下面这张图:

在这个序列当中,a1, a2到ai递增,从ai+1开始递减,并且 a i + 1 < a 1 a_{i+1} < a_1 a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值