1、乘积最大子数组
//给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
//
//
//
// 示例 1:
//
// 输入: [2,3,-2,4]
//输出: 6
//解释: 子数组 [2,3] 有最大乘积 6。
//
//
// 示例 2:
//
// 输入: [-2,0,-1]
//输出: 0
//解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
// Related Topics 数组 动态规划
**方法一:**直接遍历的方式来进行乘积的运算并比较大小
public int maxProduct(int[] nums) {
/*int max = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
int sum = 1;
for (int j = i; j < nums.length; j++) {
sum *= nums[j];
if(sum > max){
max = sum;
}
}
}
return max;
}
方法二:采用动态规划
这一题的动态规划和其他的有所不同,这个不能单单靠前面几位的结果来影响后当前位上的结果,因为当前位是正是负对乘积的大小完全是两个不同的影响。所以应该分两种情况来进行讨论,第一在当前位是正的时候,我们就想获取前面的最大乘积(正的)来与之相乘获得更大的值,第二当前位是负的时候,我们就想获取前面的最小乘积(负的)来与之相乘获得更大的值。所以状态应该用两个数组来表示,一个表示当前最小值,一个表示当前最大值,最后的公式为
minF[i] = Math.min(minF[i-1]*nums[i],Math.min(nums[i],maxF[i-1]*nums[i]))
maxF[i] = Math.max(maxF[i-1]*nums[i],Math.max(nums[i],minF[i-1]*nums[i]))
public int maxProduct(int[] nums) {
//此题的动态规划不太一样,不能直接通过一个状态转移方程来推知前后的关系,比如
// {5,6,-3,4,-3},所以转移之后{5,30,-3,4,-3},不能救简单认为最大值就是30,此时最大值其实是
// 5*6*-3*4*-3=1080,所以在每一个点我们设置以当前节点为结尾的乘积的最大值和最小值
int length = nums.length;
int[] maxF = new int[length];
int[] minF = new int[length];
maxF[0] = nums[0];
minF[0] = nums[0];
for (int i = 1; i < length; i++) {
//后面有可能负负得正
minF[i] = Math.min(minF[i-1]*nums[i], Math.min(nums[i], maxF[i-1]*nums[i]));
maxF[i] = Math.max(maxF[i-1]*nums[i], Math.max(nums[i], minF[i-1]*nums[i]));
}
int ans = maxF[0];
for (int i = 0; i < length; i++) {
if(maxF[i] > ans){
ans = maxF[i];
}
}
return ans;
}
2、打家劫舍
//你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上
//被小偷闯入,系统会自动报警。
//
// 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
//
//
//
// 示例 1:
//
//
//输入:[1,2,3,1]
//输出:4
//解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
// 偷窃到的最高金额 = 1 + 3 = 4 。
//
// 示例 2:
//
//
//输入:[2,7,9,3,1]
//输出:12
//解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
// 偷窃到的最高金额 = 2 + 9 + 1 = 12 。
//
//
//
//
// 提示:
//
//
// 1 <= nums.length <= 100
// 0 <= nums[i] <= 400
//
// Related Topics 数组 动态规划
因为金钱是不断累计的,所以我们只需要计算当前值上上个节点往前的最大值,就能得出当前的最大值,所以最大值一定是倒数第一和倒数第二个节点中的一个。
public int rob(int[] nums) {
int length = nums.length;
if(length == 1){
return nums[0];
}
if(length == 2){
return Math.max(nums[0],nums[1]);
}
int[] money = new int[length];
money[0] = nums[0];
money[1] = nums[1];
for (int i = 2; i <nums.length; i++) {
int max = 0;
for (int j = 0; j < i-1; j++) {
if(money[j] > max){
max = money[j];
}
}
money[i] = nums[i] + max;
}
return Math.max(money[length-1], money[length - 2]);
}