打家劫舍Ⅰ
题意:线性房屋,不能偷盗相邻的两个屋子。要求偷到的总金额最高
题解: 设置一个滚动数组,
l
l
l 为nums[0],
r
r
r 为nums[0] , nums[1] 的最大值,maxx = max(l + nums[i], r) 这个就很灵性了。
举个例子,如果是[1,2,3]
那么在这个过程就是:
- l l l = nums[0] = 1
- r r r = max(nums[0], nums[1]) = max(1, 2) = 2
- maxx = max( l l l + nums[i], r r r) = max(nums[0] + nums[2], max(nums[0], nums[1]) ) = max(1 + 3, 1 + 2) = 4
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0)
return 0;
if (nums.size() == 1) //如果长度为1,就只能偷一家
return nums[0];
//不能偷盗相邻的两家
int l = nums[0];
int r = max(nums[0], nums[1]);
int maxx = max(l, r);
for (int i = 2; i < nums.size(); ++i) {
maxx = max(l + nums[i], r);
int tmp = r;
r = maxx;
l = tmp;
}
return maxx;
}
};
用dp的方法就是:
找到转移方程:
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
2
]
+
n
u
m
s
[
i
]
,
d
p
[
i
−
1
]
)
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
考虑越界情况:
d
p
[
0
]
=
n
u
m
s
[
0
]
dp[0]=nums[0]
dp[0]=nums[0]
d
p
[
1
]
=
m
a
x
(
n
u
m
s
[
0
]
,
n
u
m
s
[
1
]
)
dp[1]=max(nums[0], nums[1])
dp[1]=max(nums[0],nums[1])
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0) {
return 0;
}
if (nums.size() == 1) {
return nums[0];
}
vector<int> dp = vector<int>(nums.size(), 0);
//越界情况
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < nums.size(); i++) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[size - 1];
}
};
打家劫舍Ⅱ
题意: 打家劫舍Ⅱ比打家劫舍Ⅰ多了一种情况, 环状情况,不能同时偷盗第一间和最后一间。
题解:
思路是:将环状的情况,转换为两条链状情况。
偷盗
1
1
1 ~
n
−
1
n-1
n−1 个房间的最大值以及偷盗
2
2
2 ~
n
n
n 个房间的最大值。
进行两次dp就可以了。
将二者最大值比较即可。
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0)
return 0;
if (nums.size() == 1)
return nums[0];
vector<int> dp(nums.size() + 1);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < nums.size() - 1; ++i) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
int res = dp[nums.size() - 2];
dp[0] = 0;
dp[1] = nums[1];
for (int i = 2; i < nums.size(); i++) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
res = max(res, dp[nums.size() - 1]);
return res;
}
};