LeetCode(198 & 213 & 337):打家劫舍 I-III House Robber I-III(Java)

2019.10.18 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新)

github:https://github.com/ChopinXBP/LeetCode-Babel

可以回顾一下初级版的LeetCode198:打家劫舍,这是一道一维dp,状态转移方程也很简单:

dp[i] = Math.max(dp[i - 2] + nums[cur], dp[i - 1]);

打家劫舍II

首尾互斥,打家劫舍II实际上可以拆分成打家劫舍I的两个子问题

Arrays.copyOfRange(nums, 0, nums.length - 1);
Arrays.copyOfRange(nums, 1, nums.length);

打家劫舍III

当前偷窃的最大金额可能有两种来源情况,要么偷了这家,上一家没偷;要么偷了上一家,这家没偷。因此每一个结点的dp值和前两个结点的dp值有关。

这道升级版的树状动态规划问题也可以由一维的dp延伸来,只是情况稍微复杂一些,每一个节点的dp值与三层二叉树的结点dp值相关。对于下图所示的一棵三层满二叉树来说:

      1
    /   \
   2     3
  / \   / \ 
 4   5 6   7

在每个结点的金额非负的情况下,且要保证取值结点不相邻,只可能有四种最大的取值方式:

1. 结点2 + 结点3
2. 结点1 + 结点4 + 结点5 + 结点6 + 结点7
3. 结点2 + 结点6 + 结点7
4. 结点3 + 结点4 + 结点5

那么我们可以自底向上递归进行这个dp运算,令dp[i]代表以i结点为根节点的子树的最大偷窃金额值,计算结束后将dp值直接保存在i结点的val值当中返回。可以推出状态转移方程为:

dp[root] = Max(dp[l]+dp[r], root.val+dp[ll]+dp[lr]+dp[rr]+dp[rl], dp[l]+dp[rl]+dp[rr], dp[r]+dp[lr]+dp[ll]);

分别对应上述四种情况。而观察发现,在dp[l]和dp[r]的计算中实际已经包含了dp[ll]、dp[lr]、dp[rr]、dp[rl]的取舍情况,因此可以简化为前两种情况。状态转移方程简化为:

dp[root] = Max(dp[l]+dp[r], root.val+dp[ll]+dp[lr]+dp[rr]+dp[rl]);

为了方便运算,我们一般会为dp数组赋予初值。在树状dp中同样,我们需要将每一个非叶结点作为根节点的子树构造成一棵三层满二叉树方便运算。

对于叶子结点,我们给其添加值为0的左右子结点。

对于左/右子树为空的非叶节点,我们在其左/右添加一棵两层值为0的满二叉树。


传送门:打家劫舍II

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:
输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。


package Problems;

import java.util.Arrays;

/**
 *
 * You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed.
 * All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile,
 * adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were
 * broken into on the same night.
 * Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of
 * money you can rob tonight without alerting the police.
 * 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。
 * 同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
 * 给定
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值