动态规划法:
思路:
(1)状态定义:dp[i]代表前i家能偷盗的最大金额
(2)状态初始化:如果只有一家,只能偷这家dp[0]=nums[0];如果有两家,因为是连通的,所以,只能偷较富的dp[i]=max(nums[1],nums[0])
(3)状态转移:如果大于等于3家,转移方程为:dp[i]=max(dp[i-1],dp[i-2]+nums[i])
class Solution
{
public:
int rob(vector<int>& nums)
{
int n = nums.size();
vector<int> dp;
dp.resize(n);
if(n==1) return nums[0];
else if(n==2) return max(nums[0],nums[1]);
else
{
// 状态初始化
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i = 2; i<n; i++)
{
// 状态转移
dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
}
return dp[n-1];
}
}
};
解法二、奇偶性
思路:
设置两个变量,sumOdd 和 sumEven 分别对数组的奇数和偶数元素求和。
遍历数组,索引为奇数时,将元素加到奇数和,并与偶数和比较更新成max。
偶数和同理。
返回时进行最后一次更新max。
class solution
{
public:
int rob(vector<int>& nums)
{
int sumOdd = 0; // 奇数和
int sumEven = 0; // 偶数和
for(int i = 0; i<nums.size(); i++)
{
if(i%2 == 0)
{
sumEven += nums[i];
sumEven = max(sumEven,sumOdd);
}
else
{
sumOdd += nums[i];
sumOdd = max(sumEven,sumOdd);
}
}
return max(sumOdd,sumEven);
}
};
动态规划法:
思路:
保存当前的最大值和最小值
所有最大值中最大的那个就是结果
状态定义:
dpmin[i] = 以i下标结尾的最小乘积
dpmax[i] = 以i下标结尾的最大乘积;
状态初始化:
状态转移方程:
1、nums[i] = 0
dpmin[i] = dpmax[i] = 0
2、nums[i] > 0
dpmax[i] = max(dpmax[i - 1] * nums[i], nums[i])
dpmin[i] = min(dpmin[i - 1] * nums[i], nums[i])
正数 * 较大值->较大值,正数 * 较小值->较小值
nums[i]要么续上之前的min或max,要么不续上,自己就是当前最大值或者最小值
3、nums[i] < 0
dpmax[i] = max(dpmin[i-1] * nums[i], nums[i])
dpmin[i] = min(dpmax[i-1] * nums[i], nums[i])
负数 * 较大值->较小值,负数 * 较小值->较大值
nums[i]要么续上之前的min或max,要么不续上,自己就是当前最大值或者最小值。
result = max(dpmax[i])
class Solution
{
public:
int maxProduct(vector<int> &nums)
{
int n = nums.size();
// 数组中至少存在一个数,所以nums[0]存在
// dpmin[0] = dpmax[0] = nums[0]
int dpmin = nums[0], dpmax = nums[0];
// result=max(dpmax[i]), 这里先令result = dpmax[0]
int res = dpmax;
for(int i = 1; i < n; i++)
{
if(nums[i] == 0)
{
dpmin = dpmax = 0;
}
else if(nums[i] > 0)
{
dpmax = max(dpmax * nums[i], nums[i]);
dpmin = min(dpmin * nums[i], nums[i]);
}
else
{
// tmp用来临时保存dpmax
int tmp = dpmax;
dpmax = max(dpmin * nums[i], nums[i]);
dpmin = min(tmp * nums[i], nums[i]);
}
res = max(res, dpmax);
}
return res;
}
};