程式碼隨想錄演算法訓練營第四十五天 | 打家劫舍

深蓝von發表於2024-07-02

198.打家劫舍

題目連結 文章講解 影片講解

  • dp[j]: 表示投到第j家最多能偷dp[j]的錢
  • 遞推公式: dp[j] = max(dp[j-2] + nums[j], dp[j-1])
  • 初始化:dp[0] = nums[0], dp[1] = max(dp[0], dp[1])
  • 遍歷順序:從小到大
  • 列印dp陣列
class Solution {
public:
    int rob(vector<int>& nums) {
        // dp[j]: 表示偷第j家最多能偷多少
        int n = nums.size();
        vector<int> dp(n);
        if(n == 0) return 0;
        if(n == 1) return nums[0];
        
        // 遞推公式: dp[j] = dp[j - 2] + nums[j]

        // 初始化:
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);

        for(int j = 2; j < n; ++j) {
            dp[j] = max(dp[j - 2] + nums[j], dp[j-1]);
        }

        for(int val : dp) cout << val << " ";

        return dp[n - 1];
    }
};

213.打家劫舍II

題目連結 文章講解 影片講解

思路: 首元素和尾元素只能有一個,所以分兩種情況,加入首元素和加入尾元素分別求,然後取最大的

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n);
        if(n == 0) return 0;
        if(n == 1) return nums[0];
        if(n == 2) return max(nums[0], nums[1]);

        return max(robRange(nums, 0, n -1), robRange(nums, 1, n));
    }

    int robRange(vector<int>& nums, int start, int end) {
        vector<int> dp(end);
        dp[start] = nums[start];
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for(int j = start + 2; j < end; ++j) {
            dp[j] = max(dp[j - 2] + nums[j], dp[j-1]);
        }
        return dp[end-1];
    }
};

打家劫舍III

題目連結 文章講解 影片講解

動規五部曲:

  • dp[0] dp[1]分別表示不偷當前節點得到的最大值和偷當前節點的最大值
  • 遞推公式:
    • 偷當前節點: dp[0] = cur->val + left_dp[0] + right_dp[0],如果偷了當前節點,那麼左右孩子就不可以偷了
    • 不偷當前節點:dp[1] = max(left_dp[0], left[1]) + max(right_dp[0], right_dp[1]) 分別計算左右孩子偷與不偷的最大值相加即可
  • 初始話:初始化為任意值都可以因為dp值不以來當前dp陣列,而只依賴於左右孩子的dp陣列
  • 遍歷順序:由遞推公式可知,要計算當前dp值需要先獲取左右孩子的dp值,所以應用後序遍歷
class Solution {
public:
    int rob(TreeNode* root) {
        // dp[0]表示不偷當前節點的最大值,dp[1]表示偷當前節點的最大值
        vector<int> dp = traversal(root);
        return max(dp[0], dp[1]);
    }

    vector<int> traversal(TreeNode* root) {
        if(root == nullptr) return {0, 0};

        vector<int> left_dp = traversal(root->left);
        vector<int> right_dp = traversal(root->right);
        int val1 = root->val + left_dp[0] + right_dp[0];
        int val2 = max(left_dp[0], left_dp[1]) + max(right_dp[0], right_dp[1]);
        return {val2, val1};
    }
};

相關文章