1.打家劫舍I(中等)
1.1题目
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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
来源:力扣(LeetCode) 链接:题目来源
1.2分析
?
\bullet
? 题目要求为将数组中不相邻的数取出来并使得总和最大。
?
\bullet
? 特例:对于只有一个数的数组来说,返回该数;对于两个数的数组来说,返回它们之间的较大值;
?
\bullet
? 我们用一个等长的数组dp来记录,dp[i]表示0-i可以选取的最大值。对于两个数以上的数组来说,每一个数的选取都要考虑前面两个数,当要选取下标i表示的数时,就可以加上dp[i-2]位置的值;当不选取该值时,那么它的值就为dp[i-1]。所以dp[i]最终的值就是它们两个之间的较大值。
d
p
[
i
]
=
m
a
x
(
d
p
[
i
?
2
]
+
n
u
m
s
[
i
]
,
d
p
[
i
?
1
]
)
(
i
>
2
)
dp[i] = max(dp[i-2] + nums[i] , dp[i-1] ) (i>2)
dp[i]=max(dp[i?2]+nums[i],dp[i?1])(i>2)
1.3代码(C++)
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
if(n==2) return max(nums[0],nums[1]);
nums[1] = max(nums[0],nums[1]);
for(int i=2;i<n;i++)
{
nums[i]=max(nums[i-2]+nums[i],nums[i-1]);
}
return nums[n-1];
}
};
2.打家劫舍II(中等)
2.1题目
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例 1: 输入:nums = [2,3,2] 输出:3 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2: 输入:nums = [1,2,3,1] 输出:4 解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
示例 3: 输入:nums = [0] 输出:0
提示:
1 <= nums.length <= 100 0 <= nums[i] <= 1000
来源:力扣(LeetCode) 链接:题目来源
2.2分析
?
\bullet
? 这一问在第一问的基础上添加了房屋首尾相连的条件,所以首尾两个数字之间我们最多只能选取一个。
?
\bullet
? 既然这样我们就可以将整个数组进行分割,分为 [0,n-2] 与 [1,n-1] 两个部分,分别求解它们的最大值然后再选择两个之间的较大值作为最终结果,其余情况与第一问相同。
2.3代码(C++)
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
else if(n==2) return max(nums[0],nums[1]);
else return max(judge(nums,0,n-1),judge(nums,1,n));
}
int judge(vector<int> nums,int start,int end)
{
int first=nums[start],second=max(nums[start],nums[start+1]);
for(int i=start+2;i<end;i++)
{
int temp=second;
second=max(nums[i]+first,second);
first=temp;
}
return second;
}
};
|