找出一个序列中乘积最大的连续子序列(至少包含一个数)。
样例
样例 1:
输入:[2,3,-2,4]
输出:6
样例 2:
输入:[-1,2,4,1]
输出:8
解题思路1:
常规思路两遍遍历,时间复杂度O(n^2)
public class Solution {
/**
* @param nums: An array of integers
* @return: An integer
*/
public int maxProduct(int[] nums) {
// write your code here
int res = nums[0];
for(int i=0; i<nums.length; i++){
int temp = 1;
for(int j=i; j<nums.length; j++){
temp = temp*nums[j];
res = Math.max(res, temp);
}
}
return res;
}
}
解题思路2:
动态规划。
- 确定状态:
- 最后一步: 考虑最后一个数A[n], 那么乘积最大的就是前面以n - 1为结尾的最大乘积, 再乘上这个数
- 在这里要注意, 如果A[n]是个负数, 因为负负得正, 所以我们需要以n - 1为结尾的最小乘积
- 转移方程:
- 维护两个数组, dp1[i] 和 dp2[i], dp1[i]用于记录最大乘积, dp2[i]用于记录最小乘积.
- A[i]代表数组中的第i个数
- 转移方程: 截止到i(包括i)为止,最大乘积可能是当前值nums[i],或者前i-1最大值*nums[i],若当前i为负数,而最小值也为负数,还可能是前i-1最小值*nums[i],所以取三个数的最大值。最小值同理
dp1[i] = max(nums[i], dp1[i-1]*nums[i], dp2[i-1]*nums[i]);
dp2[i] = min(nums[i], dp1[i-1]*nums[i], dp2[i-1]*nums[i]);
- 初始条件与边界情况:
- dp1[0] = A[0], dp2[0] = A[0]
- 计算顺序:
- 从左往右
- 最终结果max(i -> 0...n | dp1[i])
public class Solution {
/**
* @param nums: An array of integers
* @return: An integer
*/
public int maxProduct(int[] nums) {
// write your code here
if(nums == null || nums.length <= 0)
return 0;
int res = nums[0];
int[] dp1 = new int[nums.length]; //乘积最大子序列的值
int[] dp2 = new int[nums.length]; //乘积最小子序列的值
dp1[0] = nums[0];
dp2[0] = nums[0];
for(int i=1; i<nums.length; i++){
dp1[i] = Math.max(nums[i], Math.max(dp1[i-1]*nums[i], dp2[i-1]*nums[i]));
dp2[i] = Math.min(nums[i], Math.min(dp1[i-1]*nums[i], dp2[i-1]*nums[i]));
}
for(int i=1; i<dp1.length; i++)
res = Math.max(res, dp1[i]);
return res;
}
}