最大回撤率 和 移动数组零元素到末尾

最大回撤率
将数组中零元素移动到末尾,要求算法时间复杂度为O(n),空间复杂度为O(1)

最大回撤率: 在选定周期内任一历史时点往后推,产品净值走到最低点时的收益率回撤幅度的最大值。最大回撤率用来描述买入产品后可能出现的最糟糕情况。D为某一天的净值,i 为某一天,j 为i 后的某一天,Di 是第i 天的产品净值,Dj 是第j 天的产品净值 最大回撤率:drawdown=max [(Di - Dj) / Di]

注意这道题不能简单地找数组中最大最小值,然后计算落差,因为有时间的先后顺序存在,比如,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.

解题思路可以来看一张图:(图片来源于他人博客)
最大回撤率 和 移动数组零元素到末尾_第1张图片
其中红色曲线表示各个数据点,蓝色点表示的是某段区间内的最大值,第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))
将数组中的零元素移动到数组末尾,要求算法时间复杂度为O(n),空间复杂度为O(1)

当时我的代码是:

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]
后面面试官提醒我可以改进,于是在数组末尾可以增加一个尾指针,记录尾零的最小下标,当前指针到达尾指针处时不再走动。

还有一个最简单的方法,当数组中零较多时,记录数组长度,一次遍历输出非零数字,再补零即可。

你可能感兴趣的:(算法学习)