[英]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.