[英]Why is this code failing a test case [Max Distance]
問題:給定一個整數數組 A,求 j - i 在 A[i] <= A[j] 約束下的最大值。
如果沒有可能的解決方案,則返回 -1。
例子:
A: [3 5 4 2] Output: 2 對 (3, 4)
輸入: 9 8 7 -9 -1
預期 OUTPUT: 1
我的 OUTPUT: 0
除了上面給定的輸入之外,我嘗試的代碼適用於所有情況,誰能解釋為什么它會失敗並為我提供更正的版本?
我的代碼(Python):
class Solution:
def maximumGap(self, A):
# write your method here
m=-1
for i in range(len(A)-1):
j=len(A)-i-1
if(A[i]<=A[j]):
m=max(m,j-i)
return m
我嘗試使用 2 個循環,它通過了上述情況,但為另一個提供了 Time Limit Exceed。
m=-1
for i in range(len(A)):
for j in range(len(A)):
if(A[i]<=A[j]):
m=max(m,j-i)
return m
你不需要測試每一對。 從末尾開始搜索,直到找到>=
當前元素的元素,這將是最大的差距。
作為一項額外的優化,您可以保存該元素的j
值,並在超過它時跳出外循環。
m = -1
maxj = len(A)
for i, el in enumerate(A):
if i > maxj:
break
for j in range(len(A)-1, -1, -1):
if el <= A[j]:
m = max(m, j-i)
maxj = j
break
你有一個非常有趣的問題,我受到它的啟發,實施得非常快。 在時間解決方案上幾乎是線性的,我下面的算法使用排序並且運行時間主要由整個數組的單次排序速度決定,因此它的運行時間為O(N * Log2(N))
,其中N
是數組中的元素數。
盡管我的算法比其他解決方案更復雜,但與其他運行時間為O(N^2)
的二次解決方案相比,它在更大的N
上實現了更快的速度,OP 的問題中提供了一種這樣的二次解決方案。
在我的算法中,我們執行以下步驟:
Arg 排序輸入數組a
。 在計算機科學中,arg-sort 意味着找到使數組排序的索引順序。 換句話說,如果我有數組a
然后 arg-sort 找到索引數組sort_idxs
使得數組a[sort_idxs[i]]
對所有0 <= i < len(a)
進行排序。 這一步是通過常規的sorted()內置 function 完成的,提供的key = lambda...
參數。
查找 arg-sort 索引的反向,即查找索引數組sort_idxs_rev
使得sort_idxs_rev[sort_idxs[i]] = i
對於所有0 <= i < len(a)
。 這一步在時間上是線性的,即花費O(N)
時間。
將begin_k
和max_dist
設置為都保持值0
。 向后遍歷0 <= j < len(a)
范圍內的所有j
。 迭代時,執行步驟4.-5.
. 步驟4.-5.
取線性時間O(N)
。
在begin_k <= k < sort_idxs_rev[j]
范圍內為k
找到所有sort_idxs[k]
的最小值(表示為i
)。
更新得到最大距離的max_dist
,如果它大於之前max_dist
,則更新它以保持新值j - i
。 更新begin_k
以保存sort_idxs_rev[j] + 1
。
Output 結果max_dist
作為答案。
上述算法說明:
可以觀察到,如果我們取最右邊的值a[j]
,那么對於所有a[i] <= a[j]
,我們可以將最大距離更新為j - "(minimal such i)"
如果最大距離更小(並且最大距離開始時為0
)。
之后,我們可以從進一步的計算中刪除數組元素a[i]
使得a[i] <= a[j]
,因為沒有其他較小的j
會為所有a[i]
提供更大的距離,使得a[i] <= a[j]
。 如果其他一些j0
使得j0 < j
將給出更大的距離,則意味着j - min_i < j0 - min_i
,因此j < j0
但我們采用j0
使得j0 < j
因此矛盾。
在i
索引中找到最小元素需要線性時間O(count_i)
,而且由於這些i
從進一步計算中刪除,這意味着后續步驟將花費O(N - count_i)
時間,因此總時間為O(count_i) + O(N - count_i) = O(N)
。
我們可以通過使用先前計算的 arg-sort 和反向 arg-sort 索引找到所有小於a[j]
的元素。 因此,找到更小的元素在時間上是線性的。
所以每個j
刪除了一堆小於a[j]
的a[i]
元素。 它還將最大距離更新為此類j
的最大可能距離。
當我們從右到左迭代所有j
時,這意味着我們觀察每個j
的最大可能j
。 並且所有j
的所有最大距離的最大值將是最終解決方案,因為如果存在解決方案,則意味着它是在某個j = j_sol
點實現的,但是因為我們觀察到所有j
,所以這意味着我們也觀察到了j = j_sol
及其對應的最大距離答案。
在j
的每次迭代中,我們刪除了一堆a[i]
,我們將它們從進一步的觀察中刪除。 這意味着在每次迭代中,數組變得越來越短。 每次迭代需要線性時間O(count_i)
來找到最小的i
,其中count_i
是刪除的i
索引的數量。 由於每次迭代都會刪除相同數量count_i
並花費時間O(count_i)
找到最小值,因此j
-loop 的總運行時間為O(count_i_0) +... + O(count_i_N) = O(N)
,因為所有count_i
都等於N
總和。
當然實際上刪除數組元素a[i]
會很慢,因為 Python 的列表是這樣實現的,即刪除列表中間的元素需要很多時間,實際上是O(N)
時間。 因此,在下面的代碼中,我並沒有實際刪除元素,而是在每次迭代時將count_i
增加begin_k
數量,這樣我就可以模擬刪除元素,因為從排序數組中刪除元素只是意味着保留一些指向范圍開頭的指針,直到這個指針所有內容都被視為“已刪除”,因此我保留了這樣的begin_k
(逐漸增長count_i
),它表示已排序數組中的一個點,在此之前所有內容都被視為已刪除。
所以 arg-sort 花費了大部分時間,仍然非常快, O(N * Log2(N))
,因為 Python 中的排序是在這個時候實現的。 反向 arg-sort 需要O(N)
。 那么j
循環中的總時間也需要O(N)
。 因此,總運行時間主要由排序算法的速度決定。
如果輸入數組真的非常大,比如數十億個元素,那么我的算法將擊敗所有O(N^2)
運行時間的二次算法。 當然,要處理數十億個數組元素,必須使用C++
而不是 Python。 在 C++ 中對數十億個元素進行排序仍然很快,需要十幾秒。
在我的代碼中,如果您想從控制台獲取輸入,您可以將第一行從input_ = '3 5 4 2'
更改為input_ = input()
。 3 5 4 2
在代碼中用作固定輸入只是為了可運行的自包含示例,Stack-Overflow 的每個訪問者都可以在沒有外部依賴的情況下運行。 最終答案打印到控制台 output。
完整代碼如下:
# Input data
#input_ = '9 8 7 -9 -1'
input_ = '3 5 4 2' # input()
a = list(map(int, input_.split()))
# Arg-sort input array
sort_idxs = sorted(range(len(a)), key = lambda i: (a[i], i))
# Compute reverse of arg-sort indices
sort_idxs_rev = [0] * len(a)
for i0, i1 in enumerate(sort_idxs):
sort_idxs_rev[i1] = i0
begin_k = 0
max_dist = 0
# Linearly search for the answer
for j in range(len(a) - 1, -1, -1):
end_k = sort_idxs_rev[j]
if begin_k >= end_k:
continue
i = min(sort_idxs[k] for k in range(begin_k, end_k))
max_dist = max(max_dist, j - i)
begin_k = end_k + 1
# Output answer
print(max_dist)
輸入:
3 5 4 2
Output:
2
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.