最大子數組問題
1.背景
《算法導論》中是通過股票的購買與出售,經過問題轉換,將前一天的當天的股票差價重新表示出來,即轉爲了一個最大子數組的問題,相當於就是尋找一個數組的和最大的非空連續子數組
如 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7
找到這連續的16個數裏面的連續和最大的子數組,具體詳情可以網上搜索。
我們利用分治法來解決這個問題。
2.Python實現
#Find_max_subarray
#python3
#Yanglin Tu
def find_max_crossing_subarray(arr,low,mid,high):
left_sum = -float('inf')
sum = 0
for i in range(mid,low-1,-1):
sum = sum + arr[i]
if sum > left_sum:
left_sum = sum
max_left = i
right_sum = -float('inf')
sum = 0
for j in range(mid+1,high+1):
sum = sum + arr[j]
if sum > right_sum:
right_sum = sum
max_right = j
return (max_left,max_right,left_sum+right_sum)
def find_maximum_subarray(arr,low,high):
if low == high:
return(low,high,arr[low])
else:
mid = (low + high)//2
left_low,left_high,left_sum = find_maximum_subarray(arr,low,mid)
right_low,right_high,right_sum = find_maximum_subarray(arr,mid+1,high)
cross_low,cross_high,cross_sum = find_max_crossing_subarray(arr,low,mid,high)
if left_sum > right_sum and left_sum > cross_sum:
return(left_low,left_high,left_sum)
elif right_sum > left_sum and right_sum > cross_sum:
return(right_low,right_high,right_sum)
else:
return (cross_low,cross_high,cross_sum)
def main():
list_a = [13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
length = len(list_a)
low_a,high_a,sum_a = find_maximum_subarray(list_a,0,length-1)
print(low_a,high_a,sum_a)
if __name__ == '__main__':
main()
3.C++實現
//Find_max_subarray
//C++
//Yanglin Tu
#include <iostream>
using namespace std;
struct arr_result
{
int max_left;
int max_right;
int max_sum;
};
arr_result find_max_crossing_subarray(int arr[],int low,int mid,int high);
arr_result find_maximum_subarray(int arr[],int low,int high);
int main(){
int list_a[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int length = sizeof(list_a)/sizeof(int);
arr_result result = find_maximum_subarray(list_a,0,length-1);
cout<<result.max_left<<'\t'<<result.max_right<<'\t'<<result.max_sum<<endl;
return 0;
}
arr_result find_max_crossing_subarray(int arr[],int low,int mid,int high){
int left_sum = -0x3f3f3f3f;
int right_sum = -0x3f3f3f3f;
int sum = 0;
int i,j,max_left,max_right;
for(i = mid;i>=low;i--){
sum = sum + arr[i];
if (sum > left_sum){
left_sum = sum;
max_left = i;
}
}
sum = 0;
for(j=mid+1;j<=high;j++){
sum = sum + arr[j];
if (sum > right_sum){
right_sum = sum;
max_right = j;
}
}
arr_result result{max_left,max_right,left_sum+right_sum};
return result;
}
arr_result find_maximum_subarray(int arr[],int low,int high){
arr_result result;
if(low == high)
return result = {low,high,arr[low]};
else{
int mid = (low + high)/2;
arr_result left_result = find_maximum_subarray(arr,low,mid);
arr_result right_result = find_maximum_subarray(arr,mid+1,high);
arr_result cross_result = find_max_crossing_subarray(arr,low,mid,high);
if (left_result.max_sum > right_result.max_sum && left_result.max_sum > cross_result.max_sum)
return left_result;
else if (right_result.max_sum > left_result.max_sum && right_result.max_sum > cross_result.max_sum)
return right_result;
else
return cross_result;
}
}
4.性能分析
此算法的時間複雜度爲O(nlogn)。
5.採用一個新的思想來解決,此時間複雜度爲O(n)
使用如下思想爲最大子數組問題設計一個非遞歸的、線性時間的算法。從數組的左邊界開始,從左至右處理,記錄到目前爲止已經處理過的最大子數組。若已知A[1..j]的最大子數組,基於如下性質將解擴展爲A[1..j+1]的最大子數組:A[1..j+1]的最大子數組要麼是A[1..j]的最大子數組,要麼是某個子數組A[i..j+1] (1≤i≤j+1)。在已知A[1..j]的最大子數組的情況下,可以在線性時間內找出形如A[i..j+1]的最大子數組。
下面用Python實現
#Find_max_subarray_1
#python3
#Yanglin Tu
def find_maximum_subarray(arr):
length = len(arr)
sum = arr[0]
bounary = arr[0]
for i in range(length-1):
if bounary > 0 :
bounary += arr[i+1]
else:
bounary = arr[i+1]
if bounary > sum:
sum = bounary
return sum
def main():
list_a = [13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
sum_a = find_maximum_subarray(list_a)
print(sum_a)
if __name__ == '__main__':
main()