查看: 1978| 回复: 0
跳转到指定楼层
上一主题 下一主题
收起左侧

[高频题] 关于Kadane算法

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
”最大子数列和问题“应该是最近两年大家面试经常碰到的一道题目了,刷过题的朋友应该也知道这是用Kadane算法解的。我在面试Meta的时候就碰到了Kadane的题,在去年一年的求职过程到最后上岸大厂的过程中,Kadane算是我思考得比较深入的算法之一。

Kadane算法算是动态规划的一个分支,关于动态规划大家应该都很熟悉:它将复杂的问题分解为一组更简单的子问题,每个子问题只解决一次,然后使用基于内存的数据结构(数组、映射等)存储它们的解决方案。因此,下次出现相同的子问题时,只需查找之前计算过的解,而不用重新计算它的解,从而节省了计算时间。

那么Kadane的最经典的案例就是上文提到的“最大子数列和问题”:给定一个整数数组,任务是找出所有非空子数组可能的最大子数组和。设给定数列为A,长度为n。如果用暴力法,那我们就从A[0]遍历到A[n-1],再从A[1]遍历到A[n]-1...结果时间复杂度为O(n**2),这显然是不实际的。

所以,我们改用动态规划的思想。而Kadane算法是基础动态规划的优化,用一个指针i保存子数列,用max_sub_sum变量保存我们当前求得的最大子数列解,因此,我们可以写出引用了Kadane的基础子数列解:


代码如下:
  1. class Solution(object):
  2.          def maxSubArrayKadane(self, nums):
  3.                length = len(nums)
  4.                 max_ending_here = max_sub_sum = nums[0]
  5.                 for i in range(1,length):
  6.                          max_ending_here = max(max_ending_here+nums[i],nums[i])
  7.                          max_sub_sum = max(max_ending_here, max_sub_sum)
  8.                 return max_sub_sum</div>
复制代码
其中max_ending_here就是子问题的解:我们把目标数列缩短为以A结尾的子数列,先用子数列,然后将i向后移动,渐渐得目标的解,也就是max_sub_sum。这就是最基础的Kadane算法。

我再分享一个比较让我印象深刻的Follow up:
Best time to sell and buy stock with cold down
股票系列的问题相信大家都很熟悉,算是动态规划的经典了。最简单的股票问题没有cold down,也可以用上述动态规划的思想解决,即找到min(price)和max(profit)即可,但是,一旦加上了cold down,我们要考虑的问题就变多了。

我们依然可以使用Kdane算法的思想解答, 但这次,我们要把子问题的进度分为不同的”状态“。


Held: 持有之前购买的股票。
Sold: 刚刚卖出了一只股票,当前没有持有股票。
Reset: 把这个状态作为起点,此时没有持有股票,之前也没有卖出过股票。更重要的是,它也是Held和Sold之前的短暂状态。由于冷却规则,在售出状态后,不能立即购买,而是被迫进入复位状态。
在我们遍历price数组时,这三种状态的转换规则如下:
Sold转换为Reset,
Reset转换为Held, 或保持Reset
Held转换为Sold,或保持Held。
也就是说:
Sold[i]=hold[i-1]+price[i]
Reset[i]=max(reset[i-1],sold[i-1])
Held[i]=max(Held[i-1],reset[i-1]-price[i])

因此,这次我们在套用kadane算法时,用max找到子问题的解时,要在这三种状态中互相转换,参考代码如下:
  1. class Solution(object):
  2.     def maxProfit(self, prices):

  3.         sold, held, reset = float('-inf'), float('-inf'), 0
  4.         for price in prices:
  5.             # Alternative: the calculation is done in parallel.
  6.             # Therefore no need to keep temporary variables
  7.             #sold, held, reset = held + price, max(held, reset-price), max(reset, sold)
  8.             pre_sold = sold
  9.             sold = held + price
  10.             held = max(held, reset - price)
  11.             reset = max(reset, pre_sold)
  12.         return max(sold, reset)</div>
复制代码
[/i][/i][/i][/i][/i]

补充内容 (2022-08-28 00:45 +8:00):
求大米求大米

评分

参与人数 4大米 +15 收起 理由
chaodly + 2 给你点个赞!
zea7ot + 2 给你点个赞!
WillWang98 + 1 给你点个赞!
14417335 + 10 给你点个赞!

查看全部评分


上一篇:[刷题]刷多少,还有哪些题 就够了?
下一篇:一个Candy Crush的变种题,检查半天代码不知道为什么TLE,大家帮忙看看
您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表