leetccode 53. 最大子序和 152. 乘积最大子序列 java (局部最优和全局最优解法)
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
”局部最优和全局最优解法“:
基本思路是这样的,在每一步,维护两个变量,一个是全局最优,就是到当前元素为止最优的解是,一个是局部最优,就是必须包含当前元素的最优的解。接下来说说动态规划的递推式(这是动态规划最重要的步骤,递归式出来了,基本上代码框架也就出来了)。假设已知第i步的global[i](全局最优)和local[i](局部最优),那么第i+1步的表达式是:
local[i+1]=Math.max(A[i], local[i]+A[i]),就是局部最优是一定要包含当前元素,所以不然就是上一步的局部最优local[i]+当前元素A[i](因为local[i]一定包含第i个元素,所以不违反条件),但是如果local[i]是负的,那么加上他就不如不需要的,所以不然就是直接用A[i];
global[i+1]=Math(local[i+1],global[i]),有了当前一步的局部最优,那么全局最优就是当前的局部最优或者还是原来的全局最优(所有情况都会被涵盖进来,因为最优的解如果不包含当前元素,那么前面会被维护在全局最优里面,如果包含当前元素,那么就是这个局部最优)。
接下来分析一下复杂度,时间上只需要扫描一次数组,所以时间复杂度是O(n)。空间上我们可以看出表达式中只需要用到上一步local[i]和global[i]就可以得到下一步的结果,所以我们在实现中可以用一个变量来迭代这个结果,不需要是一个数组,也就是如程序中实现的那样,所以空间复杂度是两个变量(local和global),即O(2)=O(1)。
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
//局部最优和全局最优
int local = nums[0];
int global = nums[0];
for(int i = 1; i < nums.length; i ++){
local = Math.max(nums[i], local+nums[i]);
global = Math.max(local, global);
}
return global;
}
}
给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
class Solution {
public int maxProduct(int[] nums) {
int[] maxdp = new int[nums.length];
int[] mindp = new int[nums.length];
maxdp[0] = mindp[0] = nums[0];
for(int i = 1; i < nums.length; i++){
if(nums[i] >= 0){
maxdp[i] = Math.max(maxdp[i - 1] * nums[i], nums[i]);
mindp[i] = Math.min(mindp[i - 1] * nums[i], nums[i]);
}else{
maxdp[i] = Math.max(mindp[i - 1] * nums[i], nums[i]);
mindp[i] = Math.min(maxdp[i - 1] * nums[i], nums[i]);
}
}
int result = Integer.MIN_VALUE;
for(int i = 0; i < maxdp.length ; i++){
if(maxdp[i] > result){
result = maxdp[i];
}
}
return result;
}
}
class Solution {
public int maxProduct(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int max = nums[0], min = nums[0], result = nums[0];
for (int i = 1; i < nums.length; i++) {
int temp = max;
max = Math.max(Math.max(max * nums[i], min * nums[i]), nums[i]);
min = Math.min(Math.min(temp * nums[i], min * nums[i]), nums[i]);
if (max > result) {
result = max;
}
}
return result;
}
}