BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #95786同步于 2017/7/17
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

【问题】leetcode 644 神奇的O(n)复杂度的解法,没看懂......

intmain
2017/7/17镜像同步7 回复
leetcode 644题目 一般的解法是用二分搜索来猜测最大的平均值,逐渐逼近最终的结果。 但是评论区有人提出了O(N)复杂度的解法 他的代码: ```python def findMaxAverage(self, A, K): N = len(A) P = [0] for x in A: P.append(P[-1] + x) def d(x, y): return (P[y+1] - P[x]) / float(y+1-x) hull = collections.deque() ans = float('-inf') for j in xrange(K-1, N): while len(hull) >= 2 and d(hull[-2], hull[-1]-1) >= d(hull[-2], j-K): hull.pop() hull.append(j-K + 1) while len(hull) >= 2 and d(hull[0], hull[1]-1) <= d(hull[0], j): hull.popleft() ans = max(ans, d(hull[0], j)) return ans ``` 解释中提到的论文链接: [ Kai-min Chung, Hsueh-I Lu - An Optimal Algorithm for the Maximum-Density Segment Problem. 2008.](https://arxiv.org/pdf/cs/0311020.pdf) 研究半天没明白,很难受... 求大神解惑 [ema11]
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
ml3615556机器人#1 · 2017/7/17
他构造了一个密度严格单调递减的数组区间(这里的双端队列deque):例如【1,2,3,4】 => d(1,2) > d(2, 3) > d(3, 4) 大概就是这样。。简单解释一下,没仔细看,不太严谨 当添加一个新的元素[j - k + 1, j]进来,如果它的密度大于队列尾部,那么就融合(pop):例如【1,2,3,4】 + 5 且 d(4,5) > d(3,4) => 【1,2,3,5】 如果队列头部到新的元素密度高于队列头部密度,那么头部出栈(popleft):例如【1,2,3,4】 + 5 且 d(1,5) > d(1,2) => 【2,3,4,5】...
intmain机器人#2 · 2017/7/17
【 在 ml3615556 的大作中提到: 】 : 他构造了一个密度严格单调递减的数组区间(这里的双端队列deque):例如【1,2,3,4】 => d(1,2) > d(2, 3) > d(3, 4) : 大概就是这样。。简单解释一下,没仔细看,不太严谨 : 当添加一个新的元素[j - k + 1, j]进来,如果它的密度大于队列尾部,那么就融合(pop):例如【1,2,3,4】 + 5 且 d(4,5) > d(3,4) => 【1,2,3,5】 : ................... 首先谢谢你的回答,我从中也受到一点启发。之后我又回头去啃了啃那个论文,说下我的理解: 问题的目标是找到这样的[i, j]区间,j-i+1 >= k 而且avg(i, j)最大。 算法的整体思路就是枚举区间的右端点j, 对于每个右端点j,找出能够使[i, j]满足长度至少为k而且avg(i, j)最大这一条件,然后再在每个右端点对应的候选解中找出最大的,即是答案。 算法的关键就是找出每个j对应的i, 如果简单的使用枚举的话就是O(n*n)。 对于可能的j来说,对应的i在[0, j-k+1]之间,而且[i,j-k+1]的平均值要尽可能的大,长度要尽可能的小。这样才会使得[i,j]最优(感性上的理解).那么反过来,[0, i]就应该是均值最小,而且长度尽可能的长。 论文中的算法将区间[0, j-k+1]分段,保证每个子段中均值都是递减的(比如[9,4,5,3], 均值分别是9,6.5,6,5.2).这样一来,i必定是某个子段的第一个元素,不可能是字段中其他元素(如果是子段中间某一个元素k,那么选择子段中k后面的元素更优,因为会使得前缀的均值更小!) 这样来看讨论区的代码的话,第一个while循环是为了讲j-k+1添加到[0, j-k+1]区间中,并且更新子段。后一个while循环就是顺序判断子段,选择最优的i了。 至于如果子段对于j不是最优,那么就可以舍弃,在j之后的右端点就不必判断该子段。这一点应该也是可以证明的,详见论文(因为我实在是看不进去了,太数学了......)
ml3615556机器人#3 · 2017/7/17
有效代码就5行,没必要看论文。。把事情搞复杂了 这个算是一个dp问题 找到状态与状态转移就可以了 你分析得很对,抓住了密度递减子区间对性质(囊括第一个区间为最优),这就够了 【 在 intmain 的大作中提到: 】 : : 首先谢谢你的回答,我从中也受到一点启发。之后我又回头去啃了啃那个论文,说下我的理解: : 问题的目标是找到这样的[i, j]区间,j-i+1 >= k 而且avg(i, j)最大。 : ...................
Libertas机器人#4 · 2017/7/17
不太懂……进楼学习
Wb4syAa9机器人#5 · 2017/7/17
关键字:单调队列
intmain机器人#6 · 2017/7/19
感觉(http://blog.csdn.net/u011542204/article/details/48751763)说的不错,从斜率的角度分析,比较好理解。
lucashood机器人#7 · 2017/7/19