LeetCode11盛最多水的容器
題目說明:
給定 n 個非負整數 a1,a2,…,an,每個數代表座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。
**說明:**你不能傾斜容器,且 n 的值至少為 2。
圖中垂直線代表輸入陣列 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示為藍色部分)的最大值為 49。
示例:
輸入: [1,8,6,2,5,4,8,3,7]
輸出: 49
題目思路:
第一眼看到這題的時候,就想這題一定會有快速做出來的方法的,如果暴力來做很可能會超時,然後想了一會,沒找到方法。就用暴力法寫了,逐個遍歷比較,時間複雜度達到了 ,空間的複雜度是 的,使用的空間是固定的。
一開始的暴力寫法是這樣的:
max = 0
temp_y = 0
for i in range(len(height)-1):
if height[i] <= temp_y:
continue
else:
temp_y = height[i]
for j in range(i+1, len(height)):
x = j - i
y = height[i]
if height[j] < height[i]:
y = height[j]
temp = x * y
if temp > max:
max = temp
return max
提交之後就超時了…
然後就想了另外一個方法,想的是,先把木板(數字)進行排序,然後從低往高遍歷,因為是從低向高遍歷的,所以就不需要考慮高度的問題,只需要考慮寬度的問題即可,用當前木板的的原索引值與比其高的木板的原索引值的絕對值作為寬度。本以為這樣做起來挺好的,時間複雜度也不會很高。但是,忽略了取 max() min()
值的問題,再Python中,這兩個操作的時間複雜度是
的,所以再加上之前的遍歷操作,最後的時間複雜度還是
的。
這次的解答如下:
a = sorted(height)
index_arra = []
for item in a:
temp = height.index(item)
index_arra.append(temp)
height[temp] = -1
result = 0
for index, item in enumerate(a):
if index <= len(a)-2:
min_index = min(index_arra[index + 1:])
max_index = max(index_arra[index + 1:])
temp = abs(index_arra[index] - min_index)
if abs(index_arra[index] - max_index) > temp:
temp = abs(index_arra[index] - max_index)
current_result = temp * item
if current_result > result:
result = current_result
return result
正確解答
最後,看了提示,說用雙指標法,兩個指標從頭尾分別向中間遍歷即可。
用這個方法,關鍵是需要明白,指標移動時,是短板的指標向長板的指標移動,直到短板的指標找到下一個長板為止,如果在找到長板的途中遇到的都比之前的短板低,則可直接跳過。
我下面的解答,沒有處理短板在尋找下一個長板的過程中,遇到更小的短板的問題(加一個判斷,就不需要計算面積了,更節省時間)。不過因為時間複雜度本身就已經降低到 了,所以也就通過了。
GitHub地址:https://github.com/zhangdianlei/LeetCode_python/blob/master/src/c11.py
result = 0
start = 0
end = len(height)-1
while start < end:
x = end - start
y = min(height[start], height[end])
result = max(result, x * y)
if height[start] > height[end]:
end = end - 1
else:
start = start + 1
return result