[英]Can this greedy algorithm be more efficient?
我正在为即将到来的考试而学习,并且正在练习一个希望我实现贪心算法的问题。
我得到一个未排序的不同权重数组,其中所有 i 的 0 < weight_i。 我必须将它们全部放置,以便我使用最少数量的桩。 我不能把两个重物放在一堆上面的一个大于下面的一个。 我还必须尊重权重的顺序,所以它们必须按顺序放置。 桩没有高度限制。
一个例子:如果我有权重 {53, 21, 40, 10, 18} 我不能将 40 放在 21 之上,因为堆必须按降序排列,我不能将 21 放在 40 之上,因为这不尊重顺序。 最佳解决方案是桩 1:53、21、10 和桩 2:40 18
我的一般解决方案是遍历数组并始终选择允许重量为 go 的第一堆。 我相信这会给我一个最佳解决方案(尽管我还没有证明)。 我找不到与之相反的例子。 但这将是 O(n^2) 因为最坏的情况是我必须遍历每个元素和每个堆(我认为)
我的问题是,有没有办法将其降低到 O(n) 或 O(nlogn)? 如果有我只是没有看到它,需要一些帮助。
您的算法将给出正确的结果。
现在请注意以下几点:当按顺序访问堆并停在可以堆叠下一个值的第一个堆时,您将始终遇到堆栈按其当前顶部(最后一个)值以升序排列的情况。
您可以使用此属性来避免堆从“左到右”的迭代。 取而代之的是在一堆堆中使用二分搜索来找到可以取下一个值的第一堆。
这将为您提供O(nlogn)时间复杂度。
信不信由你,你描述的问题相当于计算最长递增子序列的长度。 关于原因,有一个巧妙的小贪婪想法。
考虑数组的最长递增子序列 (LIS)。 因为元素在索引中升序并且在值中升序,所以它们必须都在不同的堆中。 因此,所需的最小桩数等于 LIS 中的元素数。
LIS 可以使用动态规划和二进制搜索在O(NlogN)
中轻松求解。
请注意,您描述的算法与下面的算法执行相同的操作 - 它找到您可以放置项目的第一堆(使用二进制搜索),或者它创建一个新堆,因此这可以作为正确性的“证明”您的算法和降低复杂性的方法。
令dp[i]
等于长度增加的子序列末尾的最小值元素(i + 1)
。 根据您的问题重新构建它, dp[i]
也将等于ith
堆石头的重量。
from bisect import bisect_left
def lengthOfLIS(nums):
arr = []
for i in range(len(nums)):
idx = bisect_left(arr, nums[i])
if idx == len(arr):
arr.append(nums[i])
else:
arr[idx] = nums[i]
return len(arr)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.