最大子序列(有疑问)
来源:互联网 发布:mac图片浏览器 编辑:程序博客网 时间:2024/04/28 19:40
题目1:找出一个序列中乘积最大的连续子序列(至少包含一个数)。
例子:序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6。
方法:动态规划。以A[i]结尾的max product subarray同时取决于以A[i-1]结尾的max / min product subarray以及A[i]本身。因此,对每个i,需要记录min/max product两个状态:
max_product[i] = max(max_product[i-1]*A[i], min_product[i-1]*A[i], A[i])
min_product[i] = min(max_product[i-1]*A[i], min_product[i-1]*A[i], A[i])
题解:
class Solution {public: int maxProduct(int A[], int n) { if(n<=0) return 0; int ret, curMax, curMin; ret = curMax = curMin = A[0]; for(int i=1; i<n; i++) { int temp = curMax; curMax = max(max(curMax*A[i], curMin*A[i]),A[i]); curMin = min(min(temp*A[i], curMin*A[i]),A[i]); ret = max(ret, curMax); } return ret; }};
题目2:给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
例子:给出数组[−2,2,−3,4,−1,2,1,−5,3],符合要求的子数组为[4,−1,2,1],其最大和为6
挑战:要求时间复杂度为O(n)。
方法1:动态规划,复杂度O(n)。在每一步,我们维护两个变量,一个是全局最优,就是到当前元素为止最优的解是,一个是局部最优,就是必须包含当前元素的最优的解。
local[i+1]=Math.max(A[i], local[i]+A[i])
global[i+1]=Math(local[i+1],global[i])
public class Solution { /** * @param nums: a list of integers * @return: A integer indicate the sum of minimum subarray */ public int maxSubArray(ArrayList<Integer> nums) { // write your code if(nums.size()==0) return 0; int n = nums.size(); int []global = new int[n]; int []local = new int[n]; global[0] = nums.get(0); local[0] = nums.get(0); for(int i=1;i<n;i++) { local[i] = Math.max(nums.get(i),local[i-1]+nums.get(i)); global[i] = Math.max(local[i],global[i-1]); } return global[n-1]; }}
方法2:分治法,复杂度O(nlogn)。
如果将给定的序列a[1..n]分成长度相等的两段a[1..n/2]和a[n/2+1:n],分别求出这两段的最大字段和。则该给定序列的最大字段和有三种情行:
1)和a[1..n/2]的最大字段和相同。
2)和a[n/2+1:n]的最大字段和相同。
3)最大字段和包含两部分,一部分在中,另一部分在a[n/2+1..n]中。
前两种情形我们可以用递归方法求出,第三种情形可以分别求出两部分的最大字段和值再相加(注:a[1..n/2]这部分求最大字段和要以a[n/2]结束,a[n/2+1..n] 这部分求最大字段和要以a[n/2+1]开始)。序列的最大字段和即为这三种情形的最大值。
class Solution {public: int maxSubArray(int A[], int n) { //最大字段和问题 return helper(A, 0, n-1); }private: int helper(int A[], const int istart, const int iend) { if(istart == iend)return A[iend]; int middle = (istart + iend) / 2; int maxLeft = helper(A, istart, middle); int maxRight = helper(A, middle + 1, iend); int midLeft = A[middle]; int tmp = midLeft; for(int i = middle - 1; i >= istart; i--) { tmp += A[i]; if(midLeft < tmp)midLeft = tmp; } int midRight = A[middle + 1]; tmp = midRight; for(int i = middle + 2; i <= iend; i++) { tmp += A[i]; if(midRight < tmp)midRight = tmp; } return max(max(maxLeft, maxRight), midLeft + midRight); }};
方法3:(这道题的贪心思想不是很理解,不知道是否能用图形说明问题)
采用滑动窗口解决。sum 如果小于0,置为0,再加上当前值。然后再与max相比,取大的。
public class Solution { public int maxSubArray(int[] A) { if (A == null || A.length == 0) { return 0; } int max = Integer.MIN_VALUE; int sum = 0; int len = A.length; for (int i = 0; i < len; i++) { if (sum < 0) { sum = 0; } sum += A[i]; max = Math.max(max, sum); } return max; }}
题目3:给定一个整数数组,找出两个不重叠子数组使得它们的和最大。每个子数组的数字在数组中的位置应该是连续的。返回最大的和。
例子:给出数组[1, 3, -1, 2, -1, 2],这两个子数组分别为[1, 3]和[2, -1, 2]或者[1, 3, -1, 2]和[2],它们的最大和都是7
方法:分别计算每个点按从左至右和从右至左的最大子段和,对每个点计算两边和,求其中最大值。
public class Solution { /** * @param nums: A list of integers * @return: An integer denotes the sum of max two non-overlapping subarrays */ public int maxTwoSubArrays(ArrayList<Integer> nums) { if (nums.size()<2) return 0; int len = nums.size(); //Calculate the max subarray from left to right and from right to left. int[] left = new int[len]; left[0] = nums.get(0); for (int i=1;i<len;i++){ left[i] = Math.max(left[i-1]+nums.get(i), nums.get(i)); } int curMax = left[0]; for (int i=1;i<len;i++){ if (left[i]<curMax){ left[i] = curMax; } else { curMax = left[i]; } } int[] right = new int[len]; right[len-1]=nums.get(len-1); for (int i=len-2;i>=0;i--){ right[i] = Math.max(right[i+1]+nums.get(i),nums.get(i)); } curMax = right[len-1]; for (int i=len-2;i>=0;i--){ if (right[i]<curMax) { right[i] = curMax; } else { curMax = right[i]; } } //Find out the result. int res = Integer.MIN_VALUE; for (int i=0;i<len-1;i++){ if (left[i]+right[i+1]>res){ res = left[i]+right[i+1]; } } return res; }}
题目4:给定一个整数数组和一个整数k,找出k个不重叠子数组使得它们的和最大。每个子数组的数字在数组中的位置应该是连续的。返回最大的和。
例子:给出数组[-1,4,-2,3,-2,3]以及k=2,返回 8
挑战:要求时间复杂度为O(n)。
方法:动态规划。d[i][j]表示从前i个元素中选择j个子段所能达到的最大和。
d[i][j] = max{d[p][j-1]+maxSubArray(p+1,i)} (i - 1 <= p <= j - 1)
public class Solution { /** * @param nums: A list of integers * @param k: An integer denote to find k non-overlapping subarrays * @return: An integer denote the sum of max k non-overlapping subarrays */ public int maxSubArray(ArrayList<Integer> nums, int k) { if (nums.size()<k) return 0; int len = nums.size(); //d[i][j]: select j subarrays from the first i elements, the max sum we can get. int[][] d = new int[len+1][k+1]; for (int i=0;i<=len;i++) d[i][0] = 0; for (int j=1;j<=k;j++) for (int i=j;i<=len;i++){ d[i][j] = Integer.MIN_VALUE; //Initial value of endMax and max should be taken care very very carefully. int endMax = 0; int max = Integer.MIN_VALUE; for (int p=i-1;p>=j-1;p--){ endMax = Math.max(nums.get(p), endMax+nums.get(p)); max = Math.max(endMax,max); if (d[i][j]<d[p][j-1]+max) d[i][j] = d[p][j-1]+max; } } return d[len][k]; }}
题目5:求绝对值最大子序列和以及对应的区间(不会做,画图方法)
题目6:有一个包含n个元素的首尾相连的环形数组arr,计算最大的子段和。
例子:数组[1, 3, -2, 6, -1],最大子段和应该为9,对应的子段为[6, -1, 1, 3]。
题目7:输出最大子段和在原序列中的起始位置
方法:用一个数组 f[]来记录哪些元素被选入,f[i] = true表示dp[i] 的计算结果中使用了dp[i-1],这样我们可以知道,只要这样递推下去,那么最大子段和的那部分所有f[i] = true,我们只需要记录最大子段和的最后一个元素的位置,然后往前推,到第一个为f[i] = false为止。
int Work(int a[],int n){ L = R = 0; dp[0] = a[0]; f[0] = false; int ans = a[0]; for(int i=1; i<n; i++) { if(dp[i-1] < 0) { f[i] = false; dp[i] = a[i]; } else { f[i] = true; dp[i] = dp[i-1] + a[i]; } if(ans < dp[i]) { ans = dp[i]; R = i; } } for(int i=R; i>=0; i--) { if(!f[i]) { L = i; break; } } L++; R++; return ans;}
- 最大子序列(有疑问)
- 最大子序列(java)
- 最大子序列问题:给定一整数序列A1,A2,A3...An(可能有负数),求A1~An的一个最大子序列Ai~Aj的和。
- 波浪子序列(最大上升下降子序列)
- Hdu 最大连续子序列(DP)
- hdoj 1231(最大连续子序列)
- HDU 1257 (最大上升子序列)
- 最大上升(下降)子序列 小节
- HDU 1231(最大连续子序列)
- leetcode 最大子序列和(连续)
- hdu 1231(最大连续子序列)
- hdu 1087(最大递增子序列)
- uva 437 (最大子序列和)
- [LeetCode]maxSubArray(最大子序列和!!!!)
- BJFU1274 最大子序列和(分治)
- 合唱队(求最大子序列问题)
- 最大增长子序列(Java)
- 最大子序列和(O(n))
- *第三周*数据结构实践项目一【顺序表的基本运算】
- 6个Linux chkconfig命令实例 - 增加,删除,查看和修改services的自动启动选项
- 二叉树的后序非递归遍历(双栈法)
- Spring IOC介绍
- Error:Execution failed for task ':sample:dexDebug'. > com.android.ide.common.process.ProcessExceptio
- 最大子序列(有疑问)
- 程序员面试宝典-1
- 白盒测试
- GDI+实现半透明阴影
- C++Primer第五版 4.3节练习
- 发布有礼!2015 Autodesk程序商店有奖发布活动拉开序幕
- ./demoCA/newcerts: No such file or directory
- python3 编码问题
- 3.仿微信--注册界面 补充用到的类