基本的常见动态规划题目,人人为我型。
1.分解子问题
假如我是站在最后一个数字上,那么最后的结果就应该是
- 包含我在内的的一个连续子数组
- 在我之前且不包含我的连续子数组
- 我单独撑起一个数组(虽然只有一个元素)
2.确定状态
因为是乘法比较特殊,因为里面还有负数,因此有可能一个最小值的负数在遇到一个负数的时候翻身为最大的数。所以准备两个状体,一个记录最大,一个记录最小。
其中
max[i]=j 表示在第i个数字为止的连续最大乘积为j
min[i]=j 表示在第i个数字为止的连续最小乘积为j
3.确定初始状态
min[0]=min[0]=nums[0]
4.确定状态的转移方程
max[i]=max(nums[i],max[i-1]*nums[i]);
min[i]=min(nums[i],min[i-1]*nums[i]);
public int maxProduct(int[] nums){
int result=0;
if(nums==null||nums.length==0){
return result;
}
int n=nums.length;
int[] max=new int[n];
int[] min=new int[n];
max[0]=min[0]=nums[0];
result = nums[0];
for(int i=1;i<nums.length;i++){
if(nums[i]>0){
max[i]=Math.max(nums[i],max[i-1]*nums[i]);
min[i]=Math.min(nums[i],min[i-1]*nums[i]);
}else {
max[i]=Math.max(nums[i],min[i-1]*nums[i]);
min[i]=Math.min(nums[i],max[i-1]*nums[i]);
}
result=Math.max(max[i],result);
}
return result;
}
这里代码中比较明显的是以该数字结尾和该数字单独成立的情况,实际上这个全局的result变量就是承担着不以该数字结尾的所有情况
5.举一反三的求最大连续子数组和
public int maxAnd(int[] nums) {
int result = 0;
if (nums.length == 0 || nums == null) {
return result;
}
result = nums[0];
int n = nums.length;
int[] max = new int[n];
max[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
max[i] = Math.max(nums[i], max[i - 1] + nums[i]);
result = Math.max(result, max[i]);
}
return result;
}