最大子数组问题
2016-04-23 14:49
281 查看
1. 问题描述
最大子数组问题: 寻找数组的和最大的非空连续数组.
2. 问题求解
2.1 分治法求解
思想:将数组划分为两个规模一样大的子数组, 找到子数组的中间位置mid,数组A[low:high]的任何连续子数组A[i:j]的所处的位置肯定是一下三种情况之一:
(1) 完全位于子数组A[low:mid]中, low<=i<=j<=mid;
(2)完全位于子数组A[mid+1:high]中, 因此mid<i<=j<=high
(3)跨越了中点,因此low<=i<=mid<j<=high
然后再这三种情况中找到最大值.
基本情况: 数组只有一个元素;
递归情况: 当前数组大小大于1,便进行分解.
时间复杂度分析:T(n)=2T(n/2)+O(n) O(n) = nlogn
以下是java实现代码:
思路: 使用2个辅助数组, maxSum[len] 和 iSum[len] ;
其中前者maxSum[i]表示,前i个元素构成的最大子数组和,不一定包含第i个元素. 可以分为包含第i个元素和不包含第i个元素这两种情况.
后者iSum[i]表示一定包含第i个元素的最大子数组和. 这又分为2种情况:一种只包含第i个元素num[i];一种是当前元素加上包含第i-1个元素的最大值,即iSum[i-1]+num[i]
时间复杂度:O(n)
实现代码如下:
在求股票最大收益问题时,可以将股票每日价格数组转换为每天收益数组,这样原来的确定哪天买入卖出的问题便可以等价与求转换后的数组的最大子数组和.
最大子数组问题: 寻找数组的和最大的非空连续数组.
2. 问题求解
2.1 分治法求解
思想:将数组划分为两个规模一样大的子数组, 找到子数组的中间位置mid,数组A[low:high]的任何连续子数组A[i:j]的所处的位置肯定是一下三种情况之一:
(1) 完全位于子数组A[low:mid]中, low<=i<=j<=mid;
(2)完全位于子数组A[mid+1:high]中, 因此mid<i<=j<=high
(3)跨越了中点,因此low<=i<=mid<j<=high
然后再这三种情况中找到最大值.
基本情况: 数组只有一个元素;
递归情况: 当前数组大小大于1,便进行分解.
时间复杂度分析:T(n)=2T(n/2)+O(n) O(n) = nlogn
以下是java实现代码:
public static int maxArraySum(int[] num, int low, int high){ if(low==high) //基本情况 return num[low]; int mid; int leftmax=0; int rightmax=0,midmax=0; mid = (low+high)/2; leftmax=maxArraySum(num,low,mid); rightmax=maxArraySum(num,mid+1,high); midmax = maxMidArraySum(num,low,mid,high); //求以上三种情况的最大值 if(leftmax<midmax) leftmax=midmax; if(leftmax<rightmax) leftmax=rightmax; return leftmax; } //求包含中间元素值的数组的最大和 public static int maxMidArraySum(int[] num,int low,int mid,int high){ int max; //找从中间值开始左边最大的和 int leftmax=Integer.MIN_VALUE; //mid左边的最大和 ,不取0的原因是要考虑负数 int sum=0; int leftindex=mid; //存储最大子数组和的最左边的下标 for(int i=mid-1;i>=low;i--){ sum += num[i]; if(sum > leftmax){ leftmax = sum; leftindex = i; } } //找从mid开始右边的最大的和 int rightmax = Integer.MIN_VALUE;//mid右边的最大和 sum = 0; int rightindex = mid; //存储最大子数组和的最右边的下标 for(int i=mid+1;i<=high;i++){ sum += num[i]; if(sum>rightmax){ rightmax=sum; rightindex=i; } } return leftmax+num[mid]+rightmax; } public static void main(String[] args){ int[] num={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7}; System.out.println(maxArraySum(num,0,num.length-1)); }2.2 非递归/线性求解方法
思路: 使用2个辅助数组, maxSum[len] 和 iSum[len] ;
其中前者maxSum[i]表示,前i个元素构成的最大子数组和,不一定包含第i个元素. 可以分为包含第i个元素和不包含第i个元素这两种情况.
后者iSum[i]表示一定包含第i个元素的最大子数组和. 这又分为2种情况:一种只包含第i个元素num[i];一种是当前元素加上包含第i-1个元素的最大值,即iSum[i-1]+num[i]
时间复杂度:O(n)
实现代码如下:
public static int maxSum(int[] num){ int max = Integer.MIN_VALUE; int len = num.length; int[] maxSum = new int[len];//每一项记录前i个元素的最大和,不一定包含第i个元素 int[] iSum = new int[len]; //每一项记录包含当前第i个元素的最大值 maxSum[0] = num[0]; iSum[0] = num[0]; int i=1; int k0; for(;i<len;i++){ //不包含第i个元素 k0 = maxSum[i-1]; //包含第i个元素 if((iSum[i-1] + num[i]) > num[i]) iSum[i] = iSum[i-1] + num[i]; else iSum[i] = num[i]; if(iSum[i] > k0) maxSum[i] = iSum[i]; else maxSum[i] = k0; System.out.println(iSum[i] +" :" + maxSum[i]); //更新当前子数组的最大和 if(maxSum[i] > max) max = maxSum[i]; } return max; }3. 问题应用
在求股票最大收益问题时,可以将股票每日价格数组转换为每天收益数组,这样原来的确定哪天买入卖出的问题便可以等价与求转换后的数组的最大子数组和.
相关文章推荐
- 聊聊MySql系列_Index
- Hystrix学习(4)熔断
- PHP预定义变量9大超全局数组用法详解
- JQuery日期插件datepicker的使用
- LeetCode *** 306. Additive Number
- Qt实现基于G.729A(G729A)的语音聊天
- 处理mysqldump导出文件案例之文件大小为0
- 2016SDAU编程练习二1010
- shape标签总结
- 简易通讯录
- windows上安装RabbitMQ
- PHP加速器eaccelerator导致php-fpm进程卡死原因分析
- Exercise(5):最大子矩阵
- Linux字符设备注册与注销
- 正则
- 216. Combination Sum III
- 209. Minimum Size Subarray Sum
- java jsp实现网站访问量的统计
- SAR成像基础知识急救箱(零)关于傅里叶变换的几个小困惑
- Android源码分析之——下载并编译源码