问题
解决方案
1.贪心算法
思路
维护一个当前序列和变量,如果这个变量小于零,就丢弃这个变量,重新初始化为零,重新从当前索引计算序列和。每次计算之后都要与最大值进行比较。
算法步骤
- 参数初始化
- 当前序列和 : 初始化为零
- 最大序列和 : 初始化为最小整数(Integer.MIN_VALUE)
- 遍历数组
- 判断当前序列和是否需要重置
- 序列和与当前索引处元素值相加
- 判断当前序列和与最大值的大小关系
- 返回最大值
完整代码
public int maxSubArray(int[] nums){
int cur_sum = 0;
int max_sum = Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++){
if(cur_sum < 0)
cur_sum = 0;
cur_sum+=nums[i];
if(max_sum < cur_sum)
max_sum = cur_sum;
}
return max_sum;
}
2.动态规划
思路
要得到最大序列和,可以求出以每个元素为终点的最大序列和,然后取最大值。计算以当前元素为终点的序列和,只用判断上一个元素的最大序列和是否大于零,如果大于,就加在当前元素上,组成当前元素的最大序列和,如果小于或等于,则当前元素值就为最大序列和。
算法步骤
-参数初始化
序列和最大值:初始化为最小的整数(Integer.MIN_VALUE)
- 迭代
- 判断当前元素上一元素是否大于零(循环从索引为1处开始)
- 如果大于零,则将值加在当前元素上
- 判断当前元素(此时已经代表以当前元素为终点的最大序列和)与序列和最大值的关系
- 若大于序列和最大值,就把当前值存在序列值最大值中。
- 判断当前元素上一元素是否大于零(循环从索引为1处开始)
- 返回最大值
完整代码
public int maxSubArray(int[] nums){
int max_sum = Interger.MIN_VALUE;
for(int i=1;i<nums.length;i++){
if(nums[i-1] > 0)
nums[i]+=nums[i-1];
if(max_sum < nums[i];
max_sum = nums[i];
}
return max_sum;
}
3.分治法
思路
类似于快速排序,分治法将一块大的区域分成了两块小的区域,对小的区域进行类似的处理,先把小区域的结果算出来,递归返回给上一层,用底层的数据推算出上层的结果。问题的关键是,每一层所应该维护的数据是哪些:
- 每层维护的数据
- lSum: 以左边界为起点的最大序列和
- rSum:以右边界为终点的最大序列和
- nSum:整个区域内的最大序列和
- iSum:整个区域序列和
- 底层数据推上一层数据的方法
*上层的lSum: (左边区域的lSum)与 (左边区域的iSum + 右边区域的lSum) 取大- 上层的rSum:(右边区域的rSum) 与 (右边区域的iSum + 左边区域的rSum)取大
- 上层的nSum:(左边区域的nSum),(左边区域的rSum + 右边区域的lSum) 与 (右边区域的nSum)取大。
- 上层的iSum:左边区域的iSum + 右边区域的iSum
- 传递数据的方式
- 由于使用的是JAVA语言,新建一个内部类Status,其中包含四个成员变量,lSum,rSum,nSum,iSum。递归时每层递归返回一个Status对象供上一层递归使用。
- 基础数据的获得
*当区域内的元素只有一个时,返回对象内的四个变量均为该元素的值。上一层就可以不断使用这些基础数据推算自己层的信息了。
算法步骤
- 参数
- int[] nums: 目标数组
- int left: 区域的左边界索引
- int right: 区域的右边界索引
- 返回值: Status
- 步骤:
- 判断区域内元素是否只有一个
- 若是,则返回一个Status对象,该对象的所有成员变量值都为该元素的值
- 将区域一分为二,分别对每个区域调用此算法,得到对应区域的状态信息。
- 利用左右区域的状态信息计算出当前层的状态信息并返回
- 判断区域内元素是否只有一个
完整代码
class Status{
int lSum; //以左边界做起点的最大序列和
int rSum; //以右边界为终点的最大序列和
int nSum; //整个区域内的最大序列和
int iSum; //整个区域的元素和
public Status(int a, int b, int c, int d){
lSum = a;
rSum = b;
nSum = c;
iSum = d;
}
}
public int maxSubArray(int[] nums){
if(nums.length == 0)
return 0;
Status ret = pushUp(nums, 0, nums.length-1);
return ret.nSum;
}
public Status pushUp(int[] nums, int left, int right){
if(left == right)
return new Status(
nums[left],
nums[left],
nums[left],
nums[left]);
Status lStatus = pushUp(nums, left, left + (right-left)/2);
Status rStatus = pushUp(nums, left + (right-left)/2 + 1, right);
return new Status(
max(lStatus.lSum, lStatus.iSum+rStatus.lSum),
max(rStatus.rSum, rStatus.iSum + lStatus.rSum),
max(lStatus.nSum, lStatus.rSum + rStatus.lSum, rStatus.nSum),
lStatus.iSum + rStatus.iSum
);
}
public int max(int a, int b){
return a>b?a:b;
}
public int max(int a, int b, int c){
return max(max(a, b), c);
}