問題是這樣的:
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。
注意: 你不能在買入股票前賣出股票。
算法
例如:輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 =
6)的時候賣出,最大利潤 = 6-1 = 5 。
注意利潤不能是 7-1 = 6, 由於賣出價格須要大於買入價格。
數組
你固然但願 低價買進,高價賣出,這樣即可以最大化利益。但遺憾的是,在一段給定時期內,可能沒法作到。好比——最高價在前,最低價在後函數
咱們能夠很容易地設計出一個暴力方法來求解問題。簡單嘗試每對可能的買賣日期組合,只要賣出日期在買入日期以後就能夠。很明顯須要2層嵌套的循環來遍歷全部組合,所以時間複雜度O(n2)spa
爲了設計出一個運行時間更快的算法。咱們從不一樣角度來看待輸入數據。咱們的目的是尋找一段日期,使得從第一天到最後一天的股票價格增量最大。所以,咱們不在從每日價格的角度是看待數據。而是看每日價格變化。第i天的價格定義爲第i天和第i-1天的價格,那麼問題就轉換爲尋找 股票數組的最大子數組問題 咋一看,這種變化對問題求解並無陌生幫助。
雖然計算一個子數組之和所須要的時間是線性的,但計算全部子數組時,咱們能夠從新組織新的計算方式。從而利用以前計算出的子數組和來計算當前子數組的和。時間仍然是O(n2)設計
咱們考慮如何用分治法來解決最大子數組問題。使用分治法意味着忙完要將子數組分爲倆個規模儘可能相等的的子數組。也就是找到中央位置。好比mid,而後考慮求解 A[low , mid] 和 A[mid + 1 , high ] ,任何連續子數組A[i , j ] 都必然是如下三種狀況.code
function find_max_crossing_subArray(arr , low , mid , high) {
let sum1= 0 ;
let left_sum = -Infinity ;
for(let i = mid ; i >= low ; i--) {
sum1 = sum1 + arr[i] ;
if(sum1 > left_sum ) {
left_sum = sum1 ;
}
}
let right_sum = -Infinity ;
let sum2 = 0 ;
for(let j = mid + 1 ; j <= high ; j++ ) {
sum2 = sum2 + arr[j] ;
if(sum2 > right_sum ) {
right_sum = sum2 ;
}
}
//返回最大子序列的 最大值
return left_sum + right_sum ;
複製代碼
}it
可知道這個函數的時間複雜度是O(n)
如今咱們就能夠設計一個求解最大子數組的方法了。io
function find_maximun_subArray (arr , low , high) {
// 若是數組中只有一個元素 , 則返回那個元素
if( low === high ) return arr[low] ;
else {
let mid = Math.floor((low + high)/2) ;
var left_sum =
find_maximun_subArray(arr , low , mid ) ;
var right_sum =
find_maximun_subArray(arr , mid + 1 , high) ;
var cross_sum =
find_max_crossing_subArray(arr , low , mid , high) ;
} ;
return Math.max(left_sum , Math.max(right_sum , cross_sum)) ;
複製代碼
}function
總結:分治法的時間複雜度爲 O(nlogn)class