分治法应用----最大子序列和与最大子序列乘积

分治法,采用一种“分治(divide-and-conquer)”的策略。其想法是把问题分成两个大致相等的子问题,然后递归地对他们求解,这是“分”的含义。“治”阶段将两个子问题修补到一起并外加少量附加工作,最后得到整个问题的答案。分治法的思想其实是递归。

【求最大子序列和】在最大子序列和问题中,最大子序列和可能出现在三处。可能是整个数组的左半部,可能是整个数组的右半部,也有可能是跨越中间元素从而位于左右两部分之间。前面两种情况很容易使用递归来求解,第三种情况可以通过前半部分(包含左半部分最后一个元素)和最大和以及后半部分(包含有半部分第一个元素)最大和,再把二者相加得到。最后三种情况得到的三个值中,最大者就是我们所要的结果。

<span style="font-size:18px;"> public static int maxSum(int[] a,int left,int right) {
			if(left==right)return a[left];

			int center=(left+right)/2;

			int maxLeftSum=maxSum(a,left,center);
			int maxRightSum=maxSum(a,center+1,right);

			int maxLeftBorderSum=0,leftSum=0;

			for(int i=center;i>=left;i--)
			{
				leftSum+=a[i];
				if(leftSum>maxLeftBorderSum)
					maxLeftBorderSum=leftSum;
			}

			int maxRightBorderSum=0,rightSum=0;

			for(int i=center+1;i<=right;i++)
			{
				rightSum+=a[i];
				if(rightSum>maxRightBorderSum)
					maxRightBorderSum=rightSum;
			}

			return Math.max(maxRightBorderSum+maxLeftBorderSum,Math.max(maxLeftSum,maxRightSum));

		  }</span>

【求最大子序列乘积】

Find the contiguous subarray within an array (containing at least one number) which has the largest product.

For example, given the array [2,3,-2,4],

the contiguous subarray [2,3] has the largest product = 6.

对于求最大子序列乘积问题,思路和最大子序列和问题差不多,不过在第三种情况的求解时,稍微复杂一点。为什么会复杂一点呢?原因是符号问题,所以在求第三种情况时,除了要求解最大乘积,还要求解最小乘积。这个道理是很显然的。

<span style="font-size:18px;"> public static int maxProduct(int[] a) {
		return maxProduct(a,0,a.length-1);
	    }

	 public static int maxProduct(int[] a,int left,int right) {
		if(left==right)return a[left];

		int center=(left+right)/2;

		int maxLeftProduct=maxProduct(a,left,center);
		int maxRightProduct=maxProduct(a,center+1,right);

		int maxLeftBorderProduct=a[center],leftProduct=1;

		for(int i=center;i>=left;i--)
		{
			leftProduct*=a[i];
			if(leftProduct>maxLeftBorderProduct)
				maxLeftBorderProduct=leftProduct;
		}

       int minLeftBorderProduct=a[center];
       leftProduct=1;

		for(int i=center;i>=left;i--)
		{
			leftProduct*=a[i];
			if(leftProduct<minLeftBorderProduct)
				minLeftBorderProduct=leftProduct;
		}

		int maxRightBorderProduct=a[center+1],rightProduct=1;

		for(int i=center+1;i<=right;i++)
		{
			rightProduct*=a[i];
			if(rightProduct>maxRightBorderProduct)
				maxRightBorderProduct=rightProduct;
		}

       int minRightBorderProduct=a[center+1];
       rightProduct=1;

		for(int i=center+1;i<=right;i++)
		{
			rightProduct*=a[i];
			if(rightProduct<minRightBorderProduct)
				minRightBorderProduct=rightProduct;
		}

		int max1=Math.max(maxLeftProduct, maxRightProduct);
		int max2=0;
		if(maxLeftBorderProduct>0&& maxRightBorderProduct>0)max2=maxRightBorderProduct*maxLeftBorderProduct;
		else if(maxLeftBorderProduct<0&& maxRightBorderProduct<0)max2=maxRightBorderProduct*maxLeftBorderProduct;
		else max2=Math.max(maxRightBorderProduct, minLeftBorderProduct);

		int max3=Integer.MIN_VALUE;
		if(minLeftBorderProduct<0&& minRightBorderProduct<0)max3=minRightBorderProduct*minLeftBorderProduct;	

		return Math.max(max1,Math.max(max2, max3));

	  }</span>
时间: 2024-11-02 02:38:10

分治法应用----最大子序列和与最大子序列乘积的相关文章

最大子序列和,最小子序列和,最小正子序列和,最大子序列乘积

来自:<数据结构与算法分析——C语言描述>练习2.12 一. 最大子序列和 1.穷举法,O(N3) 1 int maxSequenceSum1(const int A[], int N) 2 { 3 int i, j, k, maxSum, thisSum; 4 5 maxSum = 0; 6 for (i = 0; i < N; i++) 7 { 8 for (j = i; j < N; j++) 9 { 10 thisSum = 0; 11 for (k = i; k <

HDU - 6197 array array array (最长上升子序列&amp;最长下降子序列)

题意:对于一个序列,要求去掉正好K个数字,若能使其成为不上升子序列或不下降子序列,则“A is a magic array.”,否则"A is not a magic array.\n". 分析: 1.求一遍LCS,然后在将序列逆转,求一遍LCS,分别可得最长上升子序列和最长下降子序列的长度tmp1.tmp2. 2.n - tmp1 <= k或n - tmp2 <= k即可,需要去掉的去完之后,在已经是最长上升或最长下降的序列中随便去够k个就好了. #include<

Codeforces 10D LCIS 求最长公共上升子序列及输出这个子序列 dp

题目链接:点击打开链接 题意: 给定n长的一个序列 再给定k长的一个序列 求LCIS并输出这个子序列 如有多解输出任意解.. = - = 敲的时候听着小曲儿pre的含义还没有想清楚,万万没想到就过了... #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<mat

最大上升子序列,最大下降子序列,最大非增子序列

For example,{1,5,2,4,3,5,6,4,7}的最大上升子序列是{1,2,3,5,6,7}长度为6 现已知原序列a[],如何求其最大上升子序列,最大下降子序列,最大非增子序列,最大非减子序列的长度?下面贴出两种方法:1.dp, 2.贪心+二分 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #defin

LIS LCS 最长上升子序列 最长公共子序列 ...

最长上升子序列,问题定义:http://blog.csdn.net/chenwenshi/article/details/6027086 代码: public static void getData( char[] L ) { int len = L.length; int[] f = new int[len]; String[] res = new String[len]; for( int i = 1; i < len; i++ ) { f[i] = 1; res[i] = "&quo

任意区间的最长连续递增子序列,最大连续子序列和

hdu3308 给n个数,有m个操作 U a b 表示将第a个数改成b Q a b 表示询问区间[a,b]的最长连续递增子序列. 区间询问问题且带修改,一般是用线段树来解决 那么要维护 Llen[rt], Lval[rt][2] 表示rt所对应的区间[l,r] 以l开头的最长连续递增子序列的长度, Lval[rt][0]表示子序列的最左边的值,Lval[rt][1]表示子序列最右边的值 Rlen[rt],Rval[rt][2]  表示rt所对应的区间[l,r]以r结尾的最长连续递增子序列的长度,

POJ 1836 Alignment(DP max(最长上升子序列 + 最长下降子序列))

Alignment Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 14486   Accepted: 4695 Description In the army, a platoon is composed by n soldiers. During the morning inspection, the soldiers are aligned in a straight line in front of the cap

[ACM] POJ 2796 Feel Good (求序列中子序列的和与子序列中的最小数最大乘积)

Feel Good Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9186   Accepted: 2509 Case Time Limit: 1000MS   Special Judge Description Bill is developing a new mathematical theory for human emotions. His recent investigations are dedicated

DP简单问题联系--最长递增子序列+最长公共子序列等

今天重温了一下dp问题,发现自己两个礼拜不写题目就什么都不会了...心态爆炸,感觉去考试怕是要gg了... 不过今天总结一下写的题目,全部都是基础的dp问题 第一个是 求最长不下降子序列的长度 第一行为n,表示n个数 第二行n个数 最长不下降子序列的长度 N小于5000 for  each  num  < =maxint 样例输入 3 1 2 3 样例输出 3 // // Created by 陈平 on 2018/7/8. // #include "iostream" usin