【问题标题】:Can this greedy algorithm be more efficient?这种贪心算法能更高效吗?
【发布时间】:2020-01-19 21:02:08
【问题描述】:

我正在为即将到来的考试而学习,我正在练习一个需要我实现贪心算法的问题。

我得到一个未排序的不同权重数组,其中所有 i 的 0 不将两个重物放在一堆,上面的一个大于下面的一个。我还必须尊重权重的顺序,所以它们必须按顺序放置。堆没有高度限制。

举个例子:如果我的权重是 {53, 21, 40, 10, 18},我不能将 40 放在 21 之上,因为堆必须按降序排列,我不能将 21 放在 40 之上,因为这不尊重命令。最佳解决方案是桩 1:53、21、10 和桩 2:40 18

我的一般解决方案是遍历数组并始终选择允许重量去的第一堆。我相信这会给我一个最佳解决方案(尽管我还没有证明)。我找不到与之相反的例子。但这将是 O(n^2),因为最坏的情况是我必须遍历每个元素和每个堆(我认为)

我的问题是,有没有办法将其降低到 O(n) 或 O(nlogn)?如果有,我只是没有看到它,需要一些帮助。

【问题讨论】:

  • 是否强制使用贪婪
  • “所以它们必须按顺序放置” - 你可以多次遍历数组吗?

标签: algorithm performance time greedy


【解决方案1】:

信不信由你,你描述的问题相当于计算最长递增子序列的长度。关于原因,有一个巧妙的小贪婪想法。

考虑数组的最长递增子序列 (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)

【讨论】:

  • 你能解释一下这将如何作为证据吗?我目前正在尝试证明此解决方案是最佳的,但我真的不明白如何。我需要任何可以得到的提示。
  • @mymemesarespiciest 最佳桩数不能少于 LIS 的长度。 LIS 中的每个元素都必须在不同的堆中。想一想 - LIS 是一个序列,对于每个元素,如果 i < j(索引)然后是 arr[i] < arr[j](值)。显然,如果一堆有i,那么它不可能也有j,因为ji之后,它必须在上面,但是arr[j] > arr[i]所以你不能把它放在上面-它必须在不同的堆中。因此,我们确定 LIS 中的每个元素都必须在不同的堆中,从而创建我们的下限。
  • @mymemesarespiciest 你熟悉子序列/最长递增子序列吗?我正在尽我所能帮助您理解,我只想衡量我应该做到多详细 - 算法很难:)
  • 我们如何证明最优解不能少于 LIS,但也不能多?
  • @גלעדברקן 因为 OP 描述的贪婪解决方案等同于 LIS,并且因为它确实构建了每一堆,所以有那么多堆是可能的。当我们构建 LIS 数组时,dp[i] 等于ith 堆上石头的重量。当我们更新dp 时,我们相当于在那个堆上放了一块石头。由于我们从字面上构建了最小解决方案,因此我们默认证明它也存在。最优解不可能更大,因为我们构建的解存在,所以最优解不可能更大,只能更少。但我们构建的解决方案也设置了一个下限。
【解决方案2】:

您的算法将给出正确的结果。

现在请注意以下几点:当按顺序访问堆并停在可以堆叠下一个值的第一个堆时,您将始终遇到堆按其当前顶部(最后一个)值以升序排列的情况顺序。

您可以使用此属性来避免堆从“左到右”的迭代。而是在一堆堆中使用binary search 来找到可以取下一个值的第一堆。

这会给你一个 O(nlogn) 的时间复杂度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 2015-09-07
    • 2022-12-07
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2013-07-14
    相关资源
    最近更新 更多