求最大子序列之和的四种方法

四种求最大子序列和的方法,效率一个比一个高。

方法二是方法一的改进

方法三是采用分治的思想,编写递归函数

方法四 最为巧妙,代码少,效率高,逻辑清晰

对原书中的代码做了一小点修改,能处理负数数组(结果为最小的负数)

附上代码

package chapter2;
import java.util.Random;
public class maxSubSum 
{
/*-------------------------------方法1 --------------------------------*/
    public  int maxSubSum1(int[] a)//方法1 
	{
    	    //最笨的方法,分别以每个元素为起点 计算每一种长度的和
		int sum=a[0],sumMax=a[0];
		for (int i = 0; i < a.length; i++)//每一个元素为起点 
		{
			
			for (int j = i; j < a.length; j++)//每一种子序列长度 
			{
				sum=a[i];
				for(int k=i+1;k<=j;k++)//求和
					sum+=a[k];
				if (sumMax<sum)//比较更新Max
				{
					sumMax=sum;
				}
			}
		}
		return sumMax;
	}
/*-------------------------------方法2 --------------------------------*/
public int maxSubSum2(int[] a)//方法二
{
	//方法一的改进,通过一个for循环直接得出 某个元素为起点的所有子序列的最大和
	int sum=0,sumMax;
	sumMax=a[0];
	for (int i = 0; i < a.length; i++)//选取每一个元素为起点
	{
		sum=0;
		for (int j = i; j < a.length; j++)//比较每一种序列的和
		{
			sum+=a[j];
			if (sum>sumMax) 
				sumMax=sum;
		}
		
	}
	return sumMax;
}
/*-------------------------------方法3 --------------------------------*/
public int maxSubSum3(int[] a,int left,int right)//方法三
{
	//分治策略
	//每次把数组分成左右两部分,
	//最大子序列和可能在三处出现,整个序列出现在左边或者右边,或者跨越中部
	
	if (left==right) //基本情况,left=right,只有一个元素
		return a[left];
	
	int center=(left+right)/2;//递归,继续分成左右两部分,
	int maxLeftSum=maxSubSum3(a, left, center);//返回左边的最大和
	int maxrightSum=maxSubSum3(a, center+1, right);//返回右边的最大和
	
	//计算从center为起点,分别向左和向右的最大序列和
	//center向左的最大子序列和
	int maxLeftBorderSum=a[center],leftBorderSum=a[center];
	for (int i = center-1; i >= left; i--) 
	{
		leftBorderSum+=a[i];
		if (leftBorderSum>maxLeftBorderSum) 
			maxLeftBorderSum=leftBorderSum;
	}
	//center向右的最大子序列和
	int maxrightBorderSum=a[center+1],rightBorderSum=a[center+1];
	for (int i = center+2; i <=right; i++) 
	{
		rightBorderSum+=a[i];
		if (rightBorderSum>maxrightBorderSum) 
			maxrightBorderSum=rightBorderSum;
	}
	//返回三种情况的最大值(整个在左边,整个在右边,跨区域)
	
	int max;
	max=maxLeftSum>maxrightSum? maxLeftSum:maxrightSum;
	max=max>maxLeftBorderSum+maxrightBorderSum?max:maxLeftBorderSum+maxrightBorderSum;
	return max;
}
/*-------------------------------方法4 --------------------------------*/
	public int maxSubSum4(int[] a)//方法四
	{
		//效率最高,代码最简单
		//思路:小于0的子序列(包括单个元素的情况)比较sumMax后直接抛弃,sum重置为0,继续累加
		int sum=a[0],sumMax=a[0];
		for (int i = 1; i < a.length; i++)
		{
			sum+=a[i];
			if (sum>sumMax) 
				sumMax=sum;
			if (sum<0) 
				sum=0;	
		}
		return sumMax;
	}
	public static void main(String[] args) 
	{
		
		int[] a=new int[1000];
		for (int i = 0; i < a.length; i++)//随机数给数组赋值
		{
			a[i]=(int )( (0.5-Math.random())*100);
			if (a[i]==0) 
				a[i]=-8;
		}
		maxSubSum test=new maxSubSum();
		
		System.out.println(test.maxSubSum4(a));
		System.out.println(test.maxSubSum3(a,0,999));
		System.out.println(test.maxSubSum2(a));
		System.out.println(test.maxSubSum1(a));
	}
}


  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是四种常用方法一个序列的最大连续子序列的和: 1. 蛮力法:对于每一个子序列,计算它们的和,最后找出最大值。时间复杂度为 O(n^2)。 ```python def max_subarray_sum_brute_force(nums): n = len(nums) max_sum = float("-inf") for i in range(n): cur_sum = 0 for j in range(i, n): cur_sum += nums[j] max_sum = max(max_sum, cur_sum) return max_sum ``` 2. 分治法:将序列分成左右两部分,分别左部分、右部分和跨越中点的最大子序列和,最后将三个值取最大值。时间复杂度为 O(nlogn)。 ```python def max_subarray_sum_divide_conquer(nums): n = len(nums) def max_crossing_sum(nums, left, mid, right): left_max_sum = float("-inf") cur_sum = 0 for i in range(mid, left-1, -1): cur_sum += nums[i] left_max_sum = max(left_max_sum, cur_sum) right_max_sum = float("-inf") cur_sum = 0 for i in range(mid+1, right+1): cur_sum += nums[i] right_max_sum = max(right_max_sum, cur_sum) return left_max_sum + right_max_sum def max_subarray_sum(nums, left, right): if left == right: return nums[left] mid = (left + right) // 2 left_max_sum = max_subarray_sum(nums, left, mid) right_max_sum = max_subarray_sum(nums, mid+1, right) crossing_max_sum = max_crossing_sum(nums, left, mid, right) return max(left_max_sum, right_max_sum, crossing_max_sum) return max_subarray_sum(nums, 0, n-1) ``` 3. 动态规划法:定义一个变量 cur_sum,用来记录当前的连续子序列和,如果 cur_sum 小于等于 0,则从下一个元素重新开始计算,否则继续累加。用一个变量 max_sum 记录最大的连续子序列和。时间复杂度为 O(n)。 ```python def max_subarray_sum_dp(nums): n = len(nums) cur_sum = nums[0] max_sum = nums[0] for i in range(1, n): cur_sum = max(cur_sum + nums[i], nums[i]) max_sum = max(max_sum, cur_sum) return max_sum ``` 4. Kadane算法:与动态规划法类似,但只需要一个变量 cur_sum 来记录当前的连续子序列和,不需要用一个变量 max_sum 记录最大的连续子序列和,而是在每次更新 cur_sum 的时候,同时更新最大值。时间复杂度为 O(n)。 ```python def max_subarray_sum_kadane(nums): n = len(nums) cur_sum = nums[0] max_sum = nums[0] for i in range(1, n): cur_sum = max(nums[i], cur_sum + nums[i]) max_sum = max(max_sum, cur_sum) return max_sum ``` 这四种方法的时间复杂度分别为 O(n^2)、O(nlogn)、O(n) 和 O(n),其中 Kadane算法 是最优的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值