最大回撤率
將數組中零元素移動到末尾,要求算法時間複雜度爲O(n),空間複雜度爲O(1)
注意這道題不能簡單地找數組中最大最小值,然後計算落差,因爲有時間的先後順序存在,比如,2,9,4,3這四個數,9出現在2後面,只能計算:
(9-4)/9=0.55
(9-3)/9=0.66
(4-3)/4=0.25
最大回撤率應該是0.66,起始值爲9,結束值爲3.
解題思路可以來看一張圖:(圖片來源於他人博客)
其中紅色曲線表示各個數據點,藍色點表示的是某段區間內的最大值,第5個點出我們可以看到最大落差。
numpy中有很好的工具實現這個過程:
def max_draw_down(arr):
# i 爲結束位置
i = np.argmax((np.maxinum.accumulate(arr) - arr)/np.maxinum.accumulate(arr))
if i == 0:
print("bullshit")
# j 爲開始位置
j = np.argmax(arr[:i])
return (arr[j]-arr[i])/arr[j]
‘’’
numpy.argmax 找到最大元素的下標
numpy.ufunc.accumulate :官網的解釋是 accumulate the result of applying the operator to all elements,個人理解是累加將ufunc方法應用到每個元素上後的值,比如 numpy.add.accumulate([1, 2, 3])=[1, 3, 6],numpy.multiply.accumulate([ 4, 5, 6]) = [4, 20, 120]
numpy.maxinum :compare two arrays and returns a new array containing the element-wise maxima。 比較兩個數組並返回包含最大元素的新數組。比如:
np.maxinum([2, 3, 4], [5, 1, 3]) = [5, 3, 4]
所以: numpy.maxinum.accumulate就能計算出上圖中的那些藍點,對數組中每前後兩個元素對比,保留較大的那個,直到遇到一個更大的值。
‘’’
由於我對numpy不熟,筆試的時候就沒想到這麼精簡的代碼,我的想法是,對於當前某一個值arr_i,當其爲起始值時,取後序隊列中的最小值能達到該位置的最大回撤值。(唉,其實感覺自己也是一個很笨的人,很多題目都只能想到最簡單最原始的方法)
def find_min(arr):
min_index = 0
for i in range(len(arr)):
if arr[i] < arr[min_index]:
min_index = i
return min_index
def max_down(arr):
max_d = -1
start = -1
end = -1
min_index = find_min(arr)
for i in range(len(arr)):
if i >= min_index:
min_index = find_min(arr[i + 1: ])
d = (arr[i] - arr[min_index]) / arr[i]
if d > max_d:
max_d = d
start = i
end = min_index
if max_d == 0:
print("bullshit")
else:
print(str(max_d) + "," + str(start) + "," + str(end))
當時我的代碼是:
def move_zeors(arr):
for i in range(len(arr)):
if arr[i]== 0:
arr[i], arr[len(arr)-1-i] = arr[len(arr)-1-i], arr[i]
後面面試官提醒我可以改進,於是在數組末尾可以增加一個尾指針,記錄尾零的最小下標,當前指針到達尾指針處時不再走動。
還有一個最簡單的方法,當數組中零較多時,記錄數組長度,一次遍歷輸出非零數字,再補零即可。