最大子序列和的求解

算法1

package zui_da_zi_xu_lie_de_he;

/**
 * @author hpc
 * @Date:2018-7-27下午6:10:57
 * 功能:求解最大子序列列的和,若序列中全为负数则和为0;
 * 	该算法使用穷举法,通过两个for循环列举所有的子序列,再在每一个
 * 	子序列中使用for循环求和。复杂度:O(n^3)
 */
public class AlgorithmicDemo1 {

	public static void main(String[] args) {
		
		int [] a = {1,3,-5,2,1,2,6,-3};
		
		System.out.println(maxSubSum1(a));
	}
	public static int maxSubSum1(int [] a){
		int maxsum = 0;
		
		for(int i = 0;i<a.length;i++){
			
			for(int j = i;j<a.length;j++){
				
				int thissum = 0;
				
				for(int k = i;k<=j;k++){
					
					thissum += a[k];
				}
				if(thissum>maxsum)maxsum=thissum;
			}
		}
		return maxsum;
	} 
}

 

算法2

package zui_da_zi_xu_lie_de_he;

/**
 * @author hpc
 * @Date:2018-7-27下午7:05:30
 * 功能:求解最大子序列列的和,若序列中全为负数则和为0;
 * 		该方法也是使用穷举法,只不过撤除了每举出一个子
 * 		序列都要重新运算一次和的for循环,改为在上次运算
 * 		的结果上累加。复杂度:O(n^2)
 */
public class AlgorithmicDemo2 {

	public static void main(String[] args) {
		
		int [] a = {1,3,-5,7,1,2,6,-3};
		
		System.out.println(maxSubSum2(a));
	}
	public static int maxSubSum2(int [] a){
		int maxsum = 0;
		
		for(int i = 0;i<a.length;i++){
			
			int thissum = 0;
			
			for(int j = i;j<a.length;j++){
				
				thissum += a[j];
				
				if(thissum>maxsum)maxsum=thissum;
			}
		}
		return maxsum;
	} 

}

 

算法3

package zui_da_zi_xu_lie_de_he;

/**
 * @author hpc
 * @Date:2018-7-27下午7:17:49
 * 功能:求解最大子序列列的和,若序列中全为负数则和为0;
 * 		该方法使用分治法,复杂度:O(nlogn)
 */
public class AlgorithmicDemo3 {

	public static void main(String[] args) {
		
		int [] a = {1,3,-5,7,-1,2,6,-3};
		
		System.out.println(maxSubSum3(a));
	
	}
	public static int maxSumRec(int [] a,int left,int right){//找出以left为起点,以right为终点的数组a的最大子序列的和
		
		if(left == right){
			if(a[left]>=0)
				return a[left];
			else
				return 0;
		}
		
		int center = (left+right)/2;//找出数组的分界点,把数组分成两半
		int maxleftsum = maxSumRec(a,left,center);//找出左一半最大子序列的和
		int maxrightsum = maxSumRec(a,center+1,right);//找出右一半最大子序列的和
		
		/*
		 * 把a数组序列分为两半后,产生和最大的子序列可能在左边,可能在右边,也可能两边都跨越了
		 * 所以还要找出跨越的最大值,而找出跨越的最大值也是分两部分找,也就是找出左边部分的最大值和
		 * 右边部分的最大值,再求和就得出跨越部分的最大值。但找的时候要从中间开始找,即左边部分从
		 * center开始往回找,右边部分从center+1往后找。
		 */
		
		int maxleftbordersum = 0;
		int leftbordersum = 0;
		for(int i = center;i>=left;i--){
			leftbordersum+=a[i];
			if(leftbordersum>maxleftbordersum)maxleftbordersum=leftbordersum;
		}
		
		int maxrightbordersum = 0;
		int rightbordersum = 0;
		for(int i = center+1;i<=right;i++){
			rightbordersum+=a[i];
			if(rightbordersum>maxrightbordersum)maxrightbordersum=rightbordersum;
		}
		
		return max(maxleftsum,maxrightsum,maxleftbordersum+maxrightbordersum);
		
	}
	
	
	//找出x,y,z的最大者
	public static int max(int x,int y,int z){
		int max = 0;
		return max = z>(y>x?y:x)?z:(y>x?y:x);
	}
	
	public static int maxSubSum3(int [] a){
		return maxSumRec(a,0,a.length-1);
	}
}

 

 

算法4

package zui_da_zi_xu_lie_de_he;

/**
 * @author hpc
 * @Date:2018-7-27下午8:29:13
 * 功能:求解最大子序列列的和,若序列中全为负数则和为0;
 * 		该算法复杂度:O(n)
 */
public class AlgorithmicDemo4 {

	public static void main(String[] args) {
		
		int [] a = {1,3,-5,7,1,2,6,-3};
		
		System.out.println(maxSubSum4(a));
	}
	public static int maxSubSum4(int [] a){
		
		int maxsum = 0;
		int thissum = 0;
		
		for(int i = 0;i<a.length;i++){
			
			thissum+=a[i];
			
			/*
			 * 使用了一个for循环,大大降低了复杂度。
			 * 这个算法很巧妙。既然是找最大子序列的和,
			 * 只要是互相加的因子是正数就符合条件,因为
			 * 若加了一个负数两者之和必然减少了,而互相
			 * 加的因子也不一定单纯的指一个数,也可能是
			 * 某一个子序列的和,所以首先保证序列的起点是正数,
			 * 往序列中每添加一个数更改thissum,添加完后先与
			 * maxsum比较,若大则更改maxsum,若小则再与0比较,若比0
			 * 还小则thissum清0,这表明前面的序列不可能使构成的序列和最大
			 */
			if(thissum>maxsum)maxsum=thissum;
			else if(thissum<0)thissum = 0;
				
		}
		return maxsum;
	}
}

 

 

### 最大子序列问题的C语言实现 最大子序列问题是经典的算法问题之一,其目标是从给定的一维数组中找出具有最大的一个连续子数组。以下是基于动态规划的思想来解决问题的一种高效解决方案。 #### 动态规划的核心思路 通过维护一个状态变量 `dp[i]` 表示以第 `i` 个元素为结尾的最大子数组,可以逐步更新并最终得到全局最优解。这种方法的时间复杂度为 O(n),空间复杂度可以通过优化降低至 O(1)[^2]。 下面是完整的 C 语言代码实现: ```c #include<stdio.h> long long num[200001]; long long dp[200001]; int max(int x, int y) { return (x > y) ? x : y; } int main() { int n, i, max_sum; while (scanf("%d", &n) != EOF) { for (i = 1; i <= n; i++) { scanf("%lld", &num[i]); } dp[1] = num[1]; max_sum = dp[1]; for (i = 2; i <= n; i++) { dp[i] = max(dp[i - 1] + num[i], num[i]); // 关键转移方程 if (max_sum < dp[i]) { max_sum = dp[i]; // 更新当前最大值 } } printf("%lld\n", max_sum); } return 0; } ``` 上述程序实现了动态规划求解最大子序列的方法。其中核心部分是对每个位置上的元素决定是否将其加入之前的子数组还是重新开始一个新的子数组,这一步骤由表达式 `dp[i] = max(dp[i-1] + num[i], num[i])` 完成。 如果希望进一步减少内存消耗,则可以直接省去存储整个 `dp[]` 数组的需求,在迭代过程中仅保留上一次的结果即可[^4]。 #### 另一种暴力枚举方式 除了高效的动态规划方法外,还可以采用双重循环的方式逐一尝试所有可能的子数组组合,并记录下最大的那个总。不过该策略效率较低,时间复杂度达到 O(n²)[^3]。 ```c #include <stdio.h> #define MAXN 1000 int maxsum(const int arr[], int N) { int this_sum, max_sum; max_sum = 0; for (int i = 0; i < N; i++) { // 子数组起始位置 this_sum = 0; for (int j = i; j < N; j++) { // 子数组结束位置 this_sum += arr[j]; if (this_sum > max_sum) { max_sum = this_sum; } } } return max_sum; } int main() { int arr[MAXN]; int N; scanf("%d", &N); for (int i = 0; i < N; i++) { scanf("%d", &arr[i]); } printf("%d\n", maxsum(arr, N)); return 0; } ``` 尽管此版本易于理解,但在处理大规模输入时性能表现不佳,因此推荐优先考虑更优的算法设计如前面提到过的动态规划技术。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值