house robberⅠ
思路:
對每一個當下的房子只有兩個選擇:搶或者不搶,搶的話下一個判斷要在當下+2的位置,不搶的話可以去面對下一間房子
狀態選擇,清晰明瞭:dp[i] = max(dp[i+2]+nums[i], dp[i])
代碼,暴力動態
//關注當下,對房子就兩個選擇,對這個房子偷或者不偷
class Solution {
public:
int dp(vector<int>&nums, int start)
{
if(nums.size() == 0)
return 0;
if(start >= nums.size())
return 0;
return max(dp(nums,start+1), dp(nums, start+2)+nums[start]);
}
int rob(vector<int>& nums) {
return dp(nums, 0);
}
};
不幸的是,超時了,ok,加個備忘錄,加備忘錄其實就是在複述一下上述代碼再加個memo
//關注當下,對房子就兩個選擇,對這個房子偷或者不偷
class Solution {
public:
int dp(vector<int>&nums, int start, vector<int>&memo)
{
if(memo[start] != -1)
return memo[start];
if(nums.size() == 0)
return 0;
if(start == nums.size())
return 0;
if(start == nums.size()-1)
{
memo[start] = nums[start];
return memo[start];
}
memo[start] = max(dp(nums,start+1, memo), dp(nums, start+2, memo)+nums[start]);
return memo[start];
}
int rob(vector<int>& nums) {
vector<int> memo(nums.size()+1, -1);//初始化爲-1
return dp(nums, 0, memo);
}
};
降低空間複雜度解法
因爲狀態轉移只與最近的兩個狀態有關,所以可以進一步優化,將空間複雜度降低到O(1),
先寫一下dp數組的:dp[i]= x表示從第i間房開始最多能搶到x, dp[i] = max(dp[i], dp[i+2]+nums[i])
dp數組代碼
class Solution {
public:
int rob(vector<int>& nums) {//dp[i]表示從第n間房開始搶可以搶到的最大數
int n = nums.size();
//int dp[n+2];
vector<int>dp(n+2, 0);
dp[n] = 0;//base case從n開始搶, 最後一間房是n-1,所以搶個空, 找到狀態,遍歷狀態,所以去遍歷房間數
for(int i = n-1; i>=0; i--)
{
dp[i] = max(dp[i+1], dp[i+2]+nums[i]);
}
return dp[0];//從最後開始搶,那麼只要返回最後的結果就行,就是第一間房
}
};
降低空間複雜度代碼
因爲當前狀態只與前兩個狀態相關,所以只需要用變量保留前兩個狀態就行,不需要用dp數組將所有的狀態保留下來
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
int dp_i_1 = 0;//不搶
int dp_i_2 = 0;//搶
int dp_i = 0;
for(int i= n-1; i>=0; i--)
{
dp_i = max(dp_i_1, dp_i_2+nums[i]);
dp_i_2 = dp_i_1;
dp_i_1 = dp_i;
}
return dp_i;//i就是當前的節點,遍歷完就是最後的節點
}
};