打家劫舍
- https://leetcode.cn/problems/house-robber/
描述
- 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统
- 如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
- 给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示
- 1 <= nums.length <= 100
- 0 <= nums[i] <= 400
Typescript 版算法实现
1 )方案 1
function rob(nums: number[]): number {
let nlen = nums.length;
if(!nlen) {
return;
}
// 下标为0,代表0个房屋的金额,0; 下标为1,代表第一个房屋的金额
const dp = [0, nums[0]];
for(let i=2; i<=nlen; ++i) {
// 子问题公式,计算第i个房间的,这个数组是进行累加的
dp[i] = Math.max(dp[i-2] + nums[i - 1], dp[i-1])
}
// dp数组,永远比nums数组大1
return dp[nlen];
};
- 思路
- f(k) 从前k个房屋中能够偷窃到的最大数额
- Ak = 第k个房屋的钱数
- f(k) = max(f(k-2) + Ak, f(k-1)) 这是一个子问题
- 考虑动态规划
- 步骤
- 定义子问题,f(k) = max(f(k-2) + Ak, f(k-1))
- 反复执行子问题:从2~n, 执行上述公式
2 )方案 2
function rob(nums: number[]): number {
let nlen = nums.length;
if(!nlen) {
return;
}
// 用两个变量不断代表数组的倒数两个值
let dp0 = 0;
let dp1 = nums[0];
for(let i:number = 2; i <= nlen; ++ i) {
// 子问题公式 计算第i个房间
const tmp = Math.max(dp0 + nums[i - 1], dp1);
// 更新两个工具值
dp0 = dp1;
dp1 = tmp;
}
return dp1;
}
- 这里是优化了方案1的空间复杂度,从O(n) ~ O(1) 的性能提升
3 )方案 3
function rob(nums: number[]): number {
if (nums.length === 1) {
return nums[0]
}
const dp: number[] = Array.from({
length: nums.length
})
dp[0] = nums[0]
dp[1] = Math.max(dp[0], nums[1])
for (let i = 2; i < nums.length; i++) {
dp[i] = Math.max(
dp[i - 2] + nums[i],
dp[i - 1]
)
}
return dp[dp.length - 1]
};
- 这是官方的一个示例,是方案1的变形,没有方案2好
Python3 版算法实现
1 )方案 1
class Solution:
def rob(self, nums: List[int]) -> int:
nlen = len(nums)
if not nlen:
return 0
# 下标为0,代表0个房屋的金额,0; 下标为1,代表第一个房屋的金额
dp = [0, nums[0]]
for i in range(2, nlen + 1):
# 子问题公式,计算第i个房间的,这个数组是进行累加的
dp.append(max(dp[i - 2] + nums[i - 1], dp[i - 1]))
# dp数组,永远比nums数组大1
return dp[nlen]
2 )方案 2
class Solution:
def rob(self, nums: List[int]) -> int:
nlen = len(nums)
if not nlen:
return 0
# 用两个变量不断代表数组的倒数两个值
dp0, dp1 = 0, nums[0]
for i in range(2, nlen + 1):
# 子问题公式 计算第i个房间
tmp = max(dp0 + nums[i - 1], dp1)
# 更新两个工具值
dp0, dp1 = dp1, tmp
return dp1
3 )方案 3
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(dp[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
return dp[-1]
Golang 版算法实现
1 )方案 1
func rob(nums []int) int {
nlen := len(nums)
if nlen == 0 {
return 0
}
// 下标为0,代表0个房屋的金额,0; 下标为1,代表第一个房屋的金额
dp := []int{0, nums[0]}
for i := 2; i <= nlen; i++ {
// 子问题公式,计算第i个房间的,这个数组是进行累加的
dp = append(dp, max(dp[i-2]+nums[i-1], dp[i-1]))
}
// dp数组,永远比nums数组大1
return dp[nlen]
}
// 定义一个辅助函数 max 返回两个整数中的最大值
func max(a, b int) int {
if a > b {
return a
}
return b
}
2 )方案 2
func rob(nums []int) int {
nlen := len(nums)
if nlen == 0 {
return 0
}
// 用两个变量不断代表数组的倒数两个值
dp0, dp1 := 0, nums[0]
for i := 2; i <= nlen; i++ {
// 子问题公式 计算第i个房间
tmp := max(dp0+nums[i-1], dp1)
// 更新两个工具值
dp0, dp1 = dp1, tmp
}
return dp1
}
// 定义一个辅助函数 max 返回两个整数中的最大值
func max(a, b int) int {
if a > b {
return a
}
return b
}
3 )方案 3
func rob(nums []int) int {
nlen := len(nums)
if nlen == 1 {
return nums[0]
}
dp := make([]int, nlen)
dp[0] = nums[0]
dp[1] = max(dp[0], nums[1])
for i := 2; i < nlen; i++ {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
}
return dp[nlen - 1]
}
// 定义一个辅助函数 max 返回两个整数中的最大值
func max(a, b int) int {
if a > b {
return a
}
return b
}
487



被折叠的 条评论
为什么被折叠?



