最大子数组问题之Python和C++实现

最大子数组问题

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()

猜你喜欢

转载自blog.csdn.net/qq_32531519/article/details/81206340