Open azl397985856 opened 2 years ago
DP + 记忆化搜索\ 创建新 array, array[i] 记录到达第 i 户时的最高金额
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int[] reward = new int[nums.length];
reward[0] = nums[0];
reward[1] = Math.max(reward[0], nums[1]);
for(int i = 2; i < nums.length; i++) {
reward[i] = Math.max(reward[i-1], reward[i-2]+nums[i]);
}
return reward[nums.length-1];
}
}
时间: O(n) \ 空间: O(n)
思路
每次选取dp[i]状态取决于前一个dp[i-1]与前前一个dp[i-2]加上num[i-2]最大值
代码
class Solution {
public int rob(int[] nums) {
int[] dp = new int[nums.length + 2];
for (int i = 2; i < nums.length + 2; i++) {
dp[i] = Math.max(dp[i - 2] + nums[i - 2],dp[i - 1]);
}
return dp[nums.length + 1];
}
}
复杂度
时间复杂度:O(N)
空间复杂度:O(N)
def rob(self, nums: List[int]) -> int:
prev = 0
curr = 0
for i in nums:
prev, curr = curr, max(curr, prev + i)
return curr
class Solution:
def rob(self, nums: List[int]) -> int:
# 动态规划
# method 1:
# tc: O(N) sc: O(N)
len_n = len(nums)
if len_n == 0:
return 0
if len_n == 1:
return nums[0]
dp = [0] * len_n
dp[0] = nums[0] # 只有一间房屋
dp[1] = max(nums[0],nums[1]) #只有两件房屋
#不打劫第i间房和打劫第i间房中的较大值 - 转移方程
for i in range(2,len_n):
dp[i] = max(dp[i-2]+nums[i],dp[i-1])
return dp[len_n-1]
DP
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) < 2: return max(nums)
preA = nums[0]
preB = res = max(nums[0], nums[1])
for i in range(2, len(nums)):
res = max(preA+nums[i], preB)
preA, preB = preB, res
return res
Space: O(1) Time: O(n)
// 暴力递归
public int rob1(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
return rob1(nums, nums.length - 1);
}
private int rob1(int[] nums, int i) {
if (i == 0) {
return nums[0];
}
if (i == 1) {
return Math.max(nums[0], nums[1]);
}
return Math.max(rob1(nums, i - 1), rob1(nums, i - 2) + nums[i]);
}
// 动态规划
public int rob(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int length = nums.length;
if (length == 1) {
return nums[0];
}
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[length - 1];
}
dp. At house i, if rob it, the next available house is i+2; if not rob it, next available house i+1. Innitialize a dp[] array to store the maximum money we can get by robbing from house i.
Time: O(n) Space: O(n)
class Solution {
public int rob(int[] nums) {
int[] dp = new int[nums.length+2];
for(int i=nums.length-1;i>=0;i--) {
dp[i]=Math.max(nums[i]+dp[i+2], dp[i+1]);
}
return dp[0];
}
}
https://leetcode-cn.com/problems/house-robber/
思路:解决第[i]个房子抢还是不抢的问题,抢的化:当前价值+dp[i-2],因为i-1不能抢,不抢就是dp[i-2]
dp[i]=max(dp[i-1],dp[i-2]+num[i-2]) 令dp[0]=dp[1]=0所以当前i价值等于num[i-2[] 这就是第一个决策的房子
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
dp = [0]*(len(nums)+2)
for i in range(2,len(nums)+2):
dp[i] = max(dp[i-1],dp[i-2]+nums[i-2])
return dp[len(nums)+1]
复杂度分析:
时间复杂度:O(n)遍历num
空间复杂度:O(n) 记录dp状态
由于只需要保留dp[i-1],dp[i-2]两个状态,考虑滚动数组:
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
else:
pre = nums[0]
cur = max(pre,nums[1])
for i in range(2,len(nums)):
cur, pre = max(pre + nums[i],cur),cur
return cur
空间复杂度:O(1)
Since we can't take two adjacent values, when buiding the solution, we could try to skip 1 or 2 values, but no need to more than 3 values (instead of skiping 3, we could just take the one in the middle and still satisfy the constraint.) Let dp[i] be the maximum total value we could get at index i, we know that dp[i] = nums[i] + max(dp[i-2], dp[i-3]).
class Solution {
public:
int rob(vector<int>& nums) {
if (!nums.size())
return 0;
if (nums.size() == 1)
return nums[0];
int n = nums.size();
vector<int> dp (n, 0);
dp[0] = nums[0];
dp[1] = nums[1];
for (int i = 2; i < n; i++)
dp[i] = nums[i] + ((i < 3) ? dp[i - 2] : max (dp[i - 2], dp[i - 3]));
return max(dp[n-1], dp[n-2]);
}
};
O(n)
O(n)
最优解 = max(choice_0, choice_1...choice_n-1)
choice_0 = F(0) = nums[0] + F(2), 如果抢第0家
choice_1 = F(1) = nums[1] + F(3), 如果抢第1家
choice_2 = F(2) = nums[2] + F(4), 如果抢第2家
...
choice_n-3 = F(n-3) = nums[n-3] + F(n-1), 如果抢第n-3家
choice_n-2 = F(n-2) = nums[n-2] + F(n), 如果抢第n-2家
choice_n-1 = F(n-1) = nums[n-1] + F(n+1), 如果抢第n-1家
AC
//从左往右想,从右往左推,top-down,递归
class Solution {
public int rob(int[] nums) {
int n = nums.length;
int[] dp = new int[n+2];
int res = 0;
for(int i = n + 1;i >= 2;i--){
dp[i - 2] = Math.max(nums[i - 2] + dp[i], res);
res = dp[i - 2];
}
return res;
}
}
time: O(N),遍历每个step space: O(N),都需要,存储dp值,其实可以优化到O(1),因为每一次都只是想知道next.next的值,而不是全部。
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# 用 robber 当 dp
#
rob, not_rob = 0, 0
for idx in range(len(nums)):
num = nums[idx]
rob, not_rob = not_rob + num, max(rob, not_rob)
return max(rob, not_rob)
public int rob(int[] nums) {
if (nums == null) return 0;
int n = nums.length;
if (n == 0) return 0;
if (n == 1) return nums[0];
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < n; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[n - 1];
}
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
dp = [0] * n
if n<=2:
return max(nums)
dp[0] = nums[0]
dp[1] = max(nums[0],nums[1])
for i in range(2,n):
dp[i] = max(dp[i-2]+nums[i],dp[i-1])
return dp[-1]
时间复杂度:O(N) 空间复杂度:O(N)
动态规划。dp[i] = max(dp[i−2]+nums[i], dp[i−1])
,使用两个变量即可。
class Solution:
def rob(self, nums: List[int]) -> int:
prev, curr = 0, 0
for num in nums:
prev, curr = curr, max(prev + num, curr)
return curr
时间:O(n) n为nums长度 空间:O(1)
class Solution {
public int rob(int[] nums) {
int count = 0;
if(nums.length == 0){
return 0;
}
if(nums.length == 1){
return nums[0];
}
int[] s = new int[nums.length];
s[0] = nums[0];
s[1] = Math.max(nums[0],nums[1]);
for(int i=2; i< nums.length; i++){
s[i] = Math.max(s[i-1], s[i-2]+nums[i]);
}
return s[nums.length-1];
}
}
https://leetcode.com/problems/house-robber/
注意对DP数组的定义。dp[i]表示经过第i家的最大收益,可以抢劫第i家也可以不抢。
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int[] dp = new int[nums.length + 1];
dp[0] = 0;
dp[1] = nums[0];
for (int i = 2; i <= nums.length; i++) {
dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]);
}
return dp[nums.length];
}
}
时间:O(n)
空间:O(n)
思路:
方法一、 DP题,使用两个变量second, first代表截止到第i - 1个房子和第i-2个房子时偷盗的钱数,对于第i个房子有两种状态:
完成第i个房子时的总钱数= max(偷, 不偷)
复杂度分析:
代码(C++):
方法一、
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
if (n == 1) return nums[0];
int first = nums[0];
int second = max(nums[1], nums[0]);
for (int i = 2; i < n; ++i) {
int t = second;
second = max(second, first + nums[i]);
first = t;
}
return second;
}
};
class Solution(object):
def rob(self, nums):
if not nums:
return 0
length = len(nums)
if length == 1:
return nums[0]
dp = [0 for _ in range(length)]
for i in range(length):
if i == 0:
dp[i] = nums[0]
elif i == 1:
dp[i] = max(dp[0], nums[1])
else:
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
return dp[-1]
T: O(N) S: O(N)
class Solution(object):
def rob(self, nums):
if not nums:
return 0
length = len(nums)
if length == 1:
return nums[0]
prev = nums[0]
cur = max(prev, nums[1])
for i in range(2, length):
temp = cur
cur = max(prev + nums[i], cur)
prev = temp
return cur
T: O(N) S: O(1)
思路:动态规划+空间优化
class Solution {
//滚动数组优化空间
public int rob(int[] nums) {
int n = nums.length;
// 处理边界条件
if(n == 0){
return 0;
}
if(n == 1){
return nums[0];
}
//滚动递推
int pre = nums[0];
int cur = Math.max(nums[0],nums[1]);
for(int i = 2; i < n; i++ ){
int tmp = cur;
cur = Math.max(cur, pre + nums[i]);
pre = tmp;
}
return cur;
}
}
时间复杂度:O(N) 空间复杂度:O(1)
JavaScript
/**
* https://leetcode-cn.com/problems/house-robber/
* @param {number[]} nums
* @return {number}
*/
var rob = function (nums) {
if (nums.length == 1) {
return nums[0]
} else if (nums.length == 2) {
return Math.max(nums[0], nums[1])
}
let first = nums[0] // 定义最大值 奇数值和(下标)
let second = Math.max(nums[0], nums[1]); // 定义最大值 偶数值和(下标)
for (let i = 2; i < nums.length; i++) {
let temp = second;
// 首先存储当前后一位值,可能是奇数
// 可能是偶数.交替往前相加判断,判断后的值,一直取最大值.获取到的最大值,可能是跨度超过2的最大值.
second = Math.max(first + nums[i], second);
// 保留当前相加比较前的下标的最大值
first = temp;
}
return second;
};
// 时间复杂度 O(N) // 空间复杂度 O(1)
console.log(rob([1, 2, 3, 1])) // 4 console.log(rob([1, 2, 3, 1, 5, 4, 2, 6])) // 15
https://leetcode.com/problems/house-robber/
DP
class Solution:
def rob(self, nums: List[int]) -> int:
dp = [0] * 3
for i in range(0, len(nums)):
if i > 1:
dp[i%3] = max(dp[i%3-2] + nums[i], dp[i%3-1])
elif i == 0:
dp[i] = nums[0]
else:
dp[i] = max(nums[i-1], nums[i])
return dp[len(nums)%3-1]
时间复杂度: O(N) 空间复杂度:O(1)
思路:该题的是使用动态规划来完成,来到每一个房间都有偷和不偷二种选择,偷当前的房间就不能偷前一间,于是动态转移方程就为:dp[i] = Math.max(num[i-1]+dp[i-2],dp[i-1]);(因为当前房间的状态也只和前二个房间的状态相关,所以也可以直接继续空间压缩,直接只使用二个变量来存储。)
class Solution { public int rob(int[] nums) { if(nums==null||nums.length==0)return 0; int dp[] = new int[nums.length+1]; dp[0]=0; for(int i=1;i<=nums.length;i++){ //当前的房间偷了不偷这二种情况 if(i==1){ dp[i]=nums[i-1]; }else{ dp[i]=Math.max(nums[i-1]+dp[i-2],dp[i-1]); } } return dp[nums.length]; } }
DP approach\ dp[i] = max(dp[i-1], dp[i-2] + nums[i])\ In that case, will need to deal with edge cases: when len(nums) == 0 or len(nums) == 1
class Solution:
def rob(self, nums: List[int]) -> int:
#dp[i] = max(dp[i-1], dp[i-2] + nums[i])
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
dp = [0]*len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
return dp[-1]
class Solution
{
public:
int rob(vector<int> &nums)
{
if (nums.size() == 1) return nums[0];
std::vector<int> dp(nums.size(), 0);
dp[0] = nums[0];
dp[1] = std::max(nums[0], nums[1]);
for (int ii = 2; ii < dp.size(); ii++) {
dp[ii] = std::max(dp[ii - 1], dp[ii - 2] + nums[ii]);
}
return dp[nums.size() - 1];
}
};
DP,两种状态偷/不偷
只需要-1和-2的状态,不需要存之前的
看了答案似乎可以优化空间,之后看一下
def rob(self, nums):
if not nums:
return 0
maxRob = [0]*len(nums+1)
N = len(nums)
maxRob[N], maxRob[N-1]=0,nums[N-1]
for i in range(N-2,-1,-1):
maxRob[i] = max(maxRob[i+1],maxRob[i+2]+nums[i])
return maxRob[0]
时间
O(N)
空间
O(N)
dp[i]
定义为:当小偷来到第 i 间房子的时候,能偷到的最高金额。dp[0]=nums[0]
i
间房子的时候,他有两个选择:
i
间房子,那他就不能偷第 i-1
间房子,所以能偷到的金额是 dp[i-2] + nums[i]
i
间房子,那他就可以偷第 i-1
间房子,所以能偷到的金额是 dp[i-1]
class Solution {
public:
int rob(vector<int>& nums) {
// dp[i] 表示当小偷来到第 i 间房子时,能偷到的最高金额
int n = nums.size();
vector<int> dp(n, 0);
dp[0] = nums[0];
for (int i = 1; i < n; i++) {
// 1. 偷这个房子
int a = (i - 2 >= 0 ? dp[i - 2] : 0) + nums[i];
// 2. 不偷这个房子
int b = dp[i - 1];
dp[i] = max(a, b);
}
return dp[n - 1];
}
};
dp[i]
的值只跟 dp[i-1]
以及 dp[i-2]
有关,所以可以用两个变量来记录这两个值,就不需要记录整个 dp 数组了。class Solution {
public:
int rob(vector<int>& nums) {
// dp[i] 表示当小偷来到第 i 见房子时,能偷到的最高金额
int n = nums.size();
int p1 = 0, p2 = 0;
for (int i = 1; i < n; i++) {
// 1. 偷这个房子
int a = p1 + nums[i];
// 2. 不偷这个房子
int b = p2;
p1 = p2;
p2 = max(a, b);
}
return p2;
}
};
动态规划。用maxAmt[i]
来记录选择第i个房子作为最后偷窃的房子时能偷窃到的最高金额,那么在第i个房子之前,小偷只能偷第(i - 2)或者(i - 3)个房子,状态转移方程为maxAmt[i] = max(maxAmt[i - 3] + nums[i], maxAmt[i - 2] + nums[i])
,其中i > 2。最后返回的结果考虑偷不偷最后房子,可以为maxAmt[n - 1](偷)或者maxAmt[n - 2](不偷),返回最大值即可。对于i = 1和i = 2我们分别讨论,i = 1时为nums[0], i = 2时为max(nums[0], nums[1])。
class Solution {
public int rob(int[] nums) {
int n = nums.length;
// base cases
if (n == 1) return nums[0];
if (n == 2) return Math.max(nums[0], nums[1]);
// use an array to store the maxAmt when robbing the ith house as the last one
int[] maxAmt = new int[n];
// inital states, when n >= 3
maxAmt[0] = nums[0];
maxAmt[1] = nums[1];
maxAmt[2] = nums[0] + nums[2];
for (int i = 3; i < n; i++) {
// if the ith house is to be robbed, then (i-1)th house must not be robbed. Only choices are robbing (i - 2)th house or (i - 3)th house as previous last house, because they are not adjacent to the ith house
maxAmt[i] = Math.max(maxAmt[i - 3] + nums[i], maxAmt[i - 2] + nums[i]);
}
// the maximum amount could be either choosing the last house or the second last house as the last robbing target
return Math.max(maxAmt[n - 2], maxAmt[n - 1]);
}
}
复杂度分析
title: "Day 55 198. 打家劫舍" date: 2021-11-03T13:26:11+08:00 tags: ["Leetcode", "c++", "DP"] categories: ["91-day-algorithm"] draft: true
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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
- 1、dp是原来掌握最熟练的部分,但是由于好久没分析状态方程了,居然错了许多次。
- 2、把握好状态方程即可解决问题,分析为dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
- 3、故优化空间后,跟fib一样只需要维护两个空间即可。
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]);
int dp[2];
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i = 2; i < n; i++)
{
int best = max(dp[0] + nums[i], dp[1]);
dp[0] = dp[1];
dp[1] = best;
}
return dp[1];
}
};
时间复杂度:O(n)
空间复杂度:O(1)
先打卡,明天补
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
if len(nums) == 1:
return nums[0]
dp = [0]*len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i-1], dp[i-2]+nums[i])
return dp[-1]
Solution1: We keep track of two variables. One is the max when we rob the house, the other one is the max when we don't rob the house.
Solution2: At each index, we have two choice, either we rob the house or we don't rob the house. We recursively compute the max amount for both choices. And we pick the max one.
class Solution:
def rob(self, nums: List[int]) -> int:
inclusive, exclusive = 0, 0
for n in nums:
inclusive, exclusive = n+exclusive, max(inclusive,exclusive)
return max(inclusive, exclusive)
class Solution:
def rob(self, nums: List[int]) -> int:
memo={}
def dfs(current_position):
if current_position>=len(nums):
return 0
if current_position+2 in memo:
amount1=memo[current_position+2]+nums[current_position]
else:
amount1=dfs(current_position+2)+nums[current_position]
if current_position+1 in memo:
amount2=memo[current_position+1]
else:
amount2=dfs(current_position+1)
memo[current_position]=max(amount1,amount2)
return memo[current_position]
return dfs(0)
Time: O(n)
Space: O(1)
Time: O(n)
Space: O(n)
class Solution {
public int rob(int[] nums) {
int rob = nums[0];
int notRob = 0;
for (int i = 1; i < nums.length; i++) {
int temp = rob;
rob = Math.max(rob, notRob + nums[i]);
notRob = Math.max(notRob, temp);
}
return Math.max(rob, notRob);
}
}
Time: O(n)\ Space: O(1)
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
length = len(nums)
if length == 1:
return nums[0]
else:
prev = nums[0]
cur = max(prev, nums[1])
for i in range(2, length):
cur, prev = max(prev + nums[i], cur), cur
return cur
动态规划。
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int size = nums.size();
if (size == 1) {
return nums[0];
}
vector<int> dp = vector<int>(size, 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < size; i++) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[size - 1];
}
};
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
n = len(nums)
if n == 1:
return nums[0]
dp = [0] * n
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2,n):
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
return dp[n-1]
Go Code:
func rob(nums []int) int {
if len(nums) == 1 {
return nums[0]
}
nums[1] = max(nums[0], nums[1])
for i := 2; i < len(nums); i++ {
nums[i] = max(nums[i-2]+nums[i], nums[i-1])
}
return max(nums[len(nums)-2], nums[len(nums)-1])
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
复杂度分析
令 n 为数组长度。
class Solution:
def rob(self, nums: List[int]) -> int:
dp = [0]*(len(nums)+1)
if len(nums) == 1:
return nums[0]
if len(nums) == 2:
return max(nums)
dp[0] = nums[0]
for i in range(1,len(nums)):
# i choose
tmp1 = dp[i-2] + nums[i]
# not choose i
tmp2 = dp[i-1]
dp[i] = max(tmp1,tmp2)
return max(dp)
思路: iterate through the number, maintain the maximum money we can get so far
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1]);
}
return dp[nums.length-1];
}
}
Time Complexity: O(n) Space Complexity: O(n)
动态规划
java
class Solution {
public int rob(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
if(len == 1){
return nums[0];
}else if(len == 2){
return Math.max(nums[0], nums[1]);
}
dp[0] = nums[0];
dp[1] = Math.max(nums[0],nums[1]);
for(int i = 2; i < len; i++){
dp[i] = Math.max(nums[i] + dp[i - 2],dp[i-1]);
}
return dp[len -1];
}
}
时间复杂度:O(n) 空间复杂度:O(n)
https://leetcode-cn.com/problems/house-robber/
类二进制枚举, DP
class Solution:
def rob(self, nums: List[int]) -> int:
# 二进制枚举
maxMoney = 0
@lru_cache(None)
def dfs(idx, money, prev):
nonlocal maxMoney
if money > maxMoney:
maxMoney = money
if idx == len(nums):
return
if prev != 1:
dfs(idx + 1, money + nums[idx], 1)
dfs(idx + 1, money, 0)
dfs(0, 0, 0)
return maxMoney
class Solution:
def rob(self, nums: List[int]) -> int:
# 二进制枚举
dic = dict()
def dfs(idx):
if idx >= len(nums):
return 0
if idx in dic:
return dic[idx]
# 分两种情况
# 1.偷第start个房子,然后只能从第start+2个房子开始偷
headFirst = nums[idx]
headFirst += dfs(idx + 2)
# 2.不偷第start个房子,从第start+1个房子偷
noFirst = 0
noFirst += dfs(idx + 1)
# 取两种情况的最大值
ans = max(headFirst, noFirst)
dic[idx] = ans
return ans
return dfs(0)
class Solution:
def rob(self, nums: List[int]) -> int:
# DP
if not nums:
return 0
if len(nums) == 1:
return nums[0]
dp = [0] * (len(nums) + 1)
dp[0] = 0
dp[1] = nums[0]
for i in range(2, len(nums) + 1):
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1])
return dp[-1]
todo
class Solution {
public:
int rob(vector<int>& nums) {
vector<int> dp(nums.size(),0);
if(nums.size() <=2){
return *max_element(nums.begin(),nums.end());
}
for(int i = 0; i < nums.size();i++) {
if(i == 0)
dp[i] = nums[i];
else if(i == 1) {
dp[i] = max(nums[0], nums[1]);
}
else
dp[i] = max(dp[i - 1], dp[i-2] + nums[i]);
}
return dp.back();
}
};
class Solution {
public:
int rob(vector
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
pre1, pre2 = 0, 0
for num in nums:
temp = pre1
pre1 = max(pre2 + num, pre1)
pre2 = temp
return pre1
题意就是不能打劫相邻的两间屋子。数组应该记录下当前位置能打劫到的最多的金额,那么就应该是either前一个index的值(即不打劫当前屋子)和再前一个index的值加当前屋子的金额(即不打劫前一间屋子)取最大值。因此需要initialize memo[0] memo[1]两个位置的值分别为num[0]和max(num[0],mum[1]),因为两间屋子不能同时打劫,选最大的。
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.empty()) return 0;
if (nums.size() == 1) return nums[0];
vector<int> memo(nums.size());
memo[0] = nums[0];
memo[1] = max(nums[0], nums[1]);
for (int i = 2; i < nums.size(); ++i) {
memo[i] = max(memo[i - 1], memo[i - 2] + nums[i]);
}
return memo.back();
}
};
var rob = function(nums) {
const dp = []
dp[0] = nums[0]
dp[1] = Math.max(dp[0], nums[1])
for (let i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1])
}
return dp[nums.length - 1]
};
时间:O(n) 空间:O(n)
int rob(vector<int>& nums) {
int dp[nums.size()];
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[nums.size()-1];
}
https://leetcode-cn.com/problems/house-robber/
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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
动态规划
Java Code:
class Solution {
public int rob(int[] nums) {
int[] dp = new int[nums.length];
if(nums.length == 1) return nums[0];
if(nums.length == 2) return Math.max(nums[0],nums[1]);
dp[0] = nums[0];
dp[1] = Math.max(nums[0],nums[1]);
for(int i = 2 ;i < nums.length ; i++){
dp[i] = Math.max(dp[i-2] + nums[i] , dp[i-1]);
}
return dp[nums.length - 1];
}
}
复杂度分析
令 n 为数组长度。
/**
* @param {number[]} nums
* @return {number}
*/
const rob = function(nums) {
let includePrev = 0;
let excludePrev = 0;
for (const num of nums) {
const includeCurr = excludePrev + num;
const excludeCurr = Math.max(excludePrev, includePrev);
includePrev = includeCurr;
excludePrev = excludeCurr;
}
return Math.max(includePrev, excludePrev);
};
DP problem. Using an array dp to record the maximum value that could be robbed at ith house.
Since we cannot rob two houses in a row, there are two choices at house i:
(1) Rob the i - 1th house and do not rob the current house.
(2) Rob the i - 2th house and rob the current house.
Thus dp[i] = max(dp [i-1], dp[i-2] + value[I])
class Solution:
def rob(self, nums: List[int]) -> int:
l = len(nums)
if not nums:
return 0
if l == 1:
return nums[0]
if l == 2:
return max(nums[0], nums[1])
dp = [0 for _ in range(l)]
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, l):
dp[i] = max(dp[i-1], dp[i - 2] + nums[i])
return dp[-1]
Time complexity: O(n).
Space complexity: O(n).
class 打家劫舍_198 {
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[] dp = new int[length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i< length; i++ ) { // 状态转移方程 : 只取前一个的状态 和前一个的前一个加上自身 最大的
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return Math.max(dp[length - 1], dp[length - 2]);
}
}
198. 打家劫舍
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/house-robber/
前置知识
暂无
题目描述