首页 > 试题广场 >

打家劫舍(三)

[编程题]打家劫舍(三)
  • 热度指数:1826 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
你是一个经验丰富的小偷,经过上次在街边和湖边得手后你准备挑战一次自己,你发现了一个结构如二叉树的小区,小区内每个房间都存有一定现金,你观察到除了小区入口的房间以外每个房间都有且仅有一个父房间和至多两个子房间。
问,给定一个二叉树结构的小区,如之前两次行动一样,你无法在不触动警报的情况下同时偷窃两个相邻的房间,在不触动警报的情况下最多的偷窃金额。

1.如果输入的二叉树为{2,1,2,#,2,#,1},那么形状结构如下:


小区入口的房间的值是2 ,偷窃第一层2和第三层 2,1 是最优方案。




2.如果输入的二叉树为{3,2,10},那么形状结构如下:

样例2:小区入口的房间的值是3 ,偷窃第二层 2,10 是最优方案。

数据范围:二叉树节点数量满足 ,树上的值满足
示例1

输入

{2,1,2,#,2,#,1}

输出

5
示例2

输入

{3,2,10}

输出

12
示例3

输入

{3,5,#,10}

输出

13

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
//Maxans:当前结点的最大值(递归结束后也就是根结点最大值,也就是结果)
//若当前结点要偷leftnos,rightnos用来保存 上 上 次偷的左右结点值的状态。还要加root->val
//若当前结点不偷,noselect用来保存 上 次偷了的状态。
//最后Maxans取偷或不偷的最大值。
class Solution {
public:
    void dfs(TreeNode*root,int &Maxans,int &noselect)
    {
        if(!root)return ;
        int leftnos=0,rightnos=0,leftMax=0,rightMax=0;
        dfs(root->left,leftMax,leftnos);
        dfs(root->right,rightMax,rightnos);
        noselect=leftMax+rightMax;
        Maxans=max(leftnos+rightnos+root->val,noselect);
    }
    int rob(TreeNode* root) {
        int Maxans=0,noselect=0;
        dfs(root,Maxans,noselect);
        return Maxans;
    }
};
如果你看了我(一、二)中的解法,可以把noselect理解为dp[i-1],表示上一次的状态。
因为这里是树,分了左右结点,所以可以把leftnos,rightnos,理解为dp[i-2]表示上上次的状态,然后加上当前值就表示当前状态。
发表于 2022-01-07 13:32:54 回复(1)
这一系列打家劫舍问题出得真好,循序渐进:线性DP->考虑环形的DP->树型DP。本题是一个非常明显的树型DP问题,对于每一个节点,在决定是否偷窃这个节点房间的财物时,我们还需要向左右孩子的房间索要两个信息:
  1. 偷窃孩子节点房间的财物时,得到的最大收益steal
  2. 不偷窃孩子节点房间的财物时,得到的最大收益noSteal
构建包含这两个信息的结构体Info,然后深度优先搜索,自底向上累加收益,当根节点得到信息体时,返回偷与不偷根节点房间的两个方案中,更大的那个收益就可以了。
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

class Info {
    public int steal;
    public int noSteal;
    public Info(int steal, int noSteal) {
        this.steal = steal;
        this.noSteal = noSteal;
    }
}

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    public int rob (TreeNode root) {
        // write code here
        Info info = process(root);
        return Math.max(info.steal, info.noSteal);
    }
    
    private Info process(TreeNode root) {
        if(root == null){
            return new Info(0, 0);
        }
        Info leftInfo = process(root.left);
        Info rightInfo = process(root.right);
        // 这一间偷,下面相邻的就不能偷
        int steal = root.val + leftInfo.noSteal + rightInfo.noSteal;
        // 这一间不偷,那下面相邻的可以偷可以不偷,选择收益大的方案
        int noSteal = Math.max(
            Math.max(leftInfo.steal + rightInfo.steal, 
                     leftInfo.noSteal + rightInfo.noSteal), 
            Math.max(leftInfo.steal + rightInfo.noSteal, 
                     leftInfo.noSteal + rightInfo.steal)
        );
        return new Info(steal, noSteal);
    }
}

发表于 2021-12-15 22:03:03 回复(0)
public int rob (TreeNode root) {
    // 对于每一个当前节点:
    // case 1: 偷,left和right都不能偷
    // case 2: 不偷,left和right都可以偷
    // 返回值,必须包含两种状态,偷和不偷
    Status res = getStatus(root);
    return Math.max(res.rob, res.notRob);
}

private Status getStatus(TreeNode root) {
    if (root == null) {
        return new Status(0, 0);
    }
    Status left = getStatus(root.left);
    Status right = getStatus(root.right);
    int rob = left.notRob + right.notRob + root.val;
    int notRob = Math.max(left.rob, left.notRob) + Math.max(right.rob, right.notRob);
    return new Status(rob, notRob);
}

static class Status {
    int rob;
    int notRob;
    public Status (int rob, int notRob) {
        this.rob = rob;
        this.notRob = notRob;
    }
}

发表于 2023-02-10 12:00:37 回复(0)
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    int rob(TreeNode* root) {
        // write code here
        vector<int> res =robTree(root);
        return max(res[0],res[1]);
        
    }
    //0:不偷 1:偷
    vector<int> robTree(TreeNode *cur){
        if(cur==nullptr)return vector<int>{0,0};
        //后序遍历 就最后汇总到根节点
        vector<int> left =robTree(cur->left);
        vector<int> right =robTree(cur->right);
        //偷cur 就不偷他的左和他的右
        int val1= cur->val+left[0]+right[0];
        //不偷cur 就找它左的最大值或者右的最大值之和
        int val2=max(left[0],left[1])+max(right[0],right[1]);
        return {val2,val1};
    }
};

发表于 2022-04-12 09:50:29 回复(0)
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    //mp1,mp2分别表示当前节点偷或不偷的最大金额
    HashMap<TreeNode,Integer> mp1=new HashMap();
    HashMap<TreeNode,Integer> mp2=new HashMap();
     
    public int rob (TreeNode root) {
        mp1.put(null,0);
        mp2.put(null,0);
        f(root);//递归
        return Math.max(mp1.get(root),mp2.get(root));//返回最大值
    }
    void f(TreeNode root){//递归
        if(root==null)
            return;
        f(root.left);//左递归
        f(root.right);//右递归
        mp1.put(root,root.val+mp2.get(root.left)+mp2.get(root.right));//当前节点偷
        mp2.put(root,Math.max(mp1.get(root.left),mp2.get(root.left))+Math.max(mp1.get(root.right),mp2.get(root.right)));//当前节点不偷
    }
}
发表于 2022-03-09 15:34:58 回复(0)
class Solution {
    unordered_map<TreeNode*, int> cache;
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    int rob(TreeNode* root) {
        // write code here
        return tryRob(root);
    }
    int tryRob(TreeNode* root){
        if(!root) return 0;
        if(cache.count(root)) return cache[root];
        int res1 = 0;
        if(root->left) res1 += tryRob(root->left->left) + tryRob(root->left->right);
        if(root->right) res1 += tryRob(root->right->left) + tryRob(root->right->right);
        res1 += root->val;
        int res2 = tryRob(root->left) + tryRob(root->right);
        return cache[root] = max(res1,res2);
    }
};

发表于 2022-03-05 11:57:05 回复(0)
感觉自己写得有点复杂,但是通过了。主要考虑每个节点两个状态,即是否可以偷窃(就算可以偷窃,可能也会选择不偷窃,偷窃和不偷窃情况下分别比较权衡
class Solution {
private:
    static struct Judge{
        int steal=-1;
        int nosteal=-1;
    };
    //用map记录访问过的状态,避免重复递归
    unordered_map<TreeNode*, Judge* > m;
    void ClearMap(){
        for(auto it=m.begin();it!=m.end();++it)
            delete it->second;
        m.clear();
    }
    //selectable状态表示该节点是否有偷或不偷的选择。
    int dfs(TreeNode* root,bool selectable){
        if(!root)
            return 0;
        if(m.find(root)==m.end())
            m[root]=new Judge;
        
        int result=0;
        //无论如何,该点都可以选择不偷窃
        if(m[root]->nosteal>=0)
            result=m[root]->nosteal;
        else{
            result=dfs(root->left,true)+dfs(root->right,true);
            m[root]->nosteal=result;
        }
        //如果当前节点可以选择偷窃,那试着偷窃,并和不偷窃的情况比较
        if(selectable){
            int temp;
            if(m[root]->steal>=0)
                temp=m[root]->steal;
            else{
                temp=dfs(root->left,false)+dfs(root->right,false)+root->val;
                m[root]->steal=temp; 
            }
            //选择较大的结果返回
            if(temp>result)
                result=temp;
        }
        return result;
    }
public:
    int rob(TreeNode* root) {
        int result=dfs(root,true);
        ClearMap();
        return result;
    }
};

)。

发表于 2022-02-09 02:01:08 回复(0)
有点尴尬,似乎看错题意了

一个BFS+动态规划,居然也有90%通过率。




/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };*/
class Solution{
    public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    int rob(TreeNode* root) {
        // write code here ;m, nhkllllll, ll;plo
        vector<vector<int>>vec;
        queue<TreeNode*>q;
        bfs(root,vec,q);
        vector<int>sumall;
        for(int i =0;i<vec.size();i++)           
        {
            int sum=0;
            for(int j =0;j<vec[i].size();j++)
            {
               sum+=vec[i][j]; 
            }
            sumall.push_back(sum);
            sum=0;
        }
        
        vector<int>dp(sumall.size()+1);
        dp[0]=0;
        dp[1]=sumall[0];
        for(int i=2;i<sumall.size()+1;i++)
        {
            dp[i]=max(dp[i-1],dp[i-2]+sumall[i-1]);
        }
        return dp[sumall.size()];
        
    }
    void bfs(TreeNode * root,vector<vector<int>>&vec,queue<TreeNode*>&q)
    {
        if(root==nullptr)
               return;
        q.push(root);
        vector<int>temp;
        //temp.push_back(q.front()->val);
        while(!q.empty())
        {
            int i =0;
            int n =q.size();
            for(;i<n;i++)
            {
                temp.push_back(q.front()->val);
                if(q.front()->left)
                    q.push(q.front()->left);
                if(q.front()->right)
                    q.push(q.front()->right);
                q.pop();
            }
            vec.push_back(temp);
            temp.clear();
        }
        
        return ;
    }
};

发表于 2022-01-24 23:07:26 回复(0)

问题信息

难度:
8条回答 1761浏览

热门推荐

通过挑战的用户

查看代码