动态规划-3 状态的定义和状态转移

198打家劫舍

动态规划-3 状态的定义和状态转移_第1张图片

思路就是用dp[i]表示以i结尾的能偷盗的最大金额,第i家一定是要偷的。
dp[i] =max{dp[j]}+nums[i],j=0,1,2…i-2
所以每计算一个dp[i]就要遍历i之前的所有的值找到那个最大,计算完所有的dp还要遍历一次寻找最大的那个值。
算法时间复杂度O(n平方) 空间复杂度O(n) ,但是n在一百以内,所以n平方是可以接受的。
但是平方的算法还是那个双百有点震惊
在这里插入图片描述

class Solution {
public:
    int rob(vector<int>& nums) {
        int dp[102];

        if(nums.size()==1) return nums[0];
        else if(nums.size()==2)  return nums[0]>nums[1]?nums[0]:nums[1];
        else if(nums.size()==0)  return 0;
        dp[0]=nums[0];
        dp[1]=nums[1];
        for(int i=2;i<nums.size();i++)
        {
           int res=INT_MIN;
           for(int j=0;j<i-1;j++)
           {
              if(res<dp[j]) res=dp[j];
           }
           dp[i]=nums[i]+res;
        }

        int res=INT_MIN;
        for(int i=0;i<nums.size();i++)
        {
            if(res<dp[i]) res=dp[i];
        }
        return res;

    }
};

然后去题解转了一圈,另一种转移方程就只要O(n),dp[i]就表示前i个能偷到的最大值,dp[i]=max(dp[i-2]+nums[i],dp[i-1]) emmm这其实是我的第一个思路,但是当时在纸上算算错了才放弃,才用上面那个思路的。这个状态转移方程就比上面那种写法简单了很多。依然是双百(小小的脑袋大大的疑惑)动态规划-3 状态的定义和状态转移_第2张图片

class Solution {
public:
    int rob(vector<int>& nums) {
        int dp[102];

        if(nums.size()==1) return nums[0];
        else if(nums.size()==2)  return nums[0]>nums[1]?nums[0]:nums[1];
        else if(nums.size()==0)  return 0;
        dp[0]=nums[0];
        dp[1]=nums[0]>nums[1]?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];

    }
};

213打家劫舍2

动态规划-3 状态的定义和状态转移_第3张图片

和上题的区别就在于数组是循环的,第0间和最后一间不可以同时偷盗,想到直接在1的基础上加上一个起始点和终止点来计算

class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();
        if(n==0) return 0;
        else if(n==1) return nums[0];
        else if(n==2) return nums[0]>nums[1]?nums[0]:nums[1];
        
        return max(rob1(nums,0,n-2),rob1(nums,1,n-1));
    } 
    int rob1(vector<int>& nums,int start,int end) {
        int dp[102];
        dp[start]=nums[start];
        dp[start+1]=nums[start]>nums[start+1]?nums[start]:nums[start+1];
        for(int i=start+2;i<=end;i++)
        {
           dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
        }
        return dp[end];

    }

  
};

337打家劫舍3

动态规划-3 状态的定义和状态转移_第4张图片

二叉树,不说了先复习二叉树去了

对于一个子树来说,有两种情况:
1.包含当前根节点
2.不包含当前根节点

情况1

由于包含了根节点,所以不能选择左右儿子节点,这种情况的最大值为:当前节点 + 左儿子情况2 + 右儿子情况2

情况2

根节点不包含,则左右儿子节点都可以选择包含或者不包含,这种情况最大值为max(左儿子情况1,左儿子情况2)+max(右儿子情况1,右儿子情况2)

深度优先,从叶子节点遍历到根节点

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    pair<int,int> dfs(TreeNode* root)//深度优先
    {
       if(root==NULL)  return {0,0};
       else
       {
           auto left_node=dfs(root->left);
           auto right_node=dfs(root->right);
           return {root->val+left_node.second+right_node.second,
                   max(left_node.first,left_node.second)+max(right_node.first,right_node.second)};
       }
    }
    int rob(TreeNode* root) {
        auto res=dfs(root);
        return max(res.first,res.second);
    }
};

你可能感兴趣的:(动态规划-3 状态的定义和状态转移)