Leetcode (213)| 打家劫舍 2

点击上方“Jerry的算法和NLP”,选择“星标”公众号

      重磅干货,第一时间送达

微信公众号:Jerry的算法和NLP

题目

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

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

examlple:

示例 1:

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

示例 2:

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

分析:

这应该是动态规划的一道比较中等的题目了,上一次讲到的题目是他的弟弟:

Leetcode (198)|  打家劫舍

考虑所有可能的抢劫方案过于困难,而且复杂度一定会超时

抓住题目中的条件,

  • 相邻两个房屋不能同时偷窃 

  • 房屋之间形成了一个环

这意味着要抢第一个屋,最后一个屋就不能抢

抢最后一个屋,第一个屋就不能抢

而且抢了这个第N个屋子,N+1和N-1的屋子也不能抢

首先考虑下Base case

n=0 return 0

n=1 return nums[0]

n=2 假设为a,b要么抢a 要么抢b return max(nums)

n=3 假设为a,b,c 要么抢a,要么b,要么c  return max(nums)

n=4 假设为a,b,c,d

  1. 如果我一开始打算抢a,那么d我是够不着了,所以我只能从a,b,c里进行递归

  2. 如果我一开始不打算抢b,那么d是在我考虑的范围内,我从b,c,d里进行挑选

对于 n >=4,有两个选项:

  1. 抢第1个房子,去掉最后一个房子。

  2. 不抢第1个房子,保留最后一个房子。

显然,你想选择数额更大的选项。于是,可以总结出公式:

所以你只需要考虑两种情况,然后就两种情况的最大值取最大即可。

代码:

python

 1class Solution:
 2    def rob(self, nums: List[int]) -> int:
 3        if not nums:
 4            return 0
 5        if len(nums)<=3:
 6            return max(nums)
 7        if len(nums)==4:
 8            return max(nums[0]+nums[2],nums[1]+nums[3])
 9        step=[0 for i in range(len(nums))]
10        step[0],step[1],step[2]=nums[0],nums[1],nums[0]+nums[2]
11        for i in range(3,len(nums)-1):
12            step[i]=max(step[i-2],step[i-3])+nums[i]
13        temp=max(step)
14        step=[0 for i in range(len(nums))]
15        step[1],step[2],step[3]=nums[1],nums[2],nums[1]+nums[3]
16        for j in range(4,len(nums)):
17            step[j]=max(step[j-2],step[j-3])+nums[j]
18        temp2=max(step)
19        return max(temp,temp2)

C++

 1int rob(vector<int>& nums)
 2{
 3    if (nums.size() == 1) return nums[0];
 4
 5    int sumOdd[2] = {0, 0}; // 0 == head, 1 == tail
 6    int sumEven[2] = { 0, 0 };
 7    for (int i = 0; i < nums.size(); i++)
 8    {
 9        for (int j = 0; j < 2; j++)
10        {
11            if (i == 0 && j == 1) continue; // head only
12            if (i == nums.size() - 1 && j == 0) continue;   // tail only
13            if (i % 2 == 0)
14            {
15                sumOdd[j] = max(sumOdd[j], sumEven[j]);
16                sumEven[j] += nums[i];
17            }
18            else
19            {
20                sumEven[j] = max(sumOdd[j], sumEven[j]);
21                sumOdd[j] += nums[i];
22            }
23        }
24    }
25
26    for (int j = 0; j < 2; j++)
27    {
28        sumOdd[j] = max(sumOdd[j], sumEven[j]);
29    }
30    return max(sumOdd[0], sumOdd[1]);
31}

后记

2020大厂笔试 | 网易提前批(1) 

2020大厂笔试 | 网易提前批(2) 

背包九讲(1)0/1背包问题

背包九讲(2)完全背包问题

数据结构类题目

具体算法类题目

  • 斐波那契数列

    • 007-斐波拉契数列

    • 008-跳台阶

    • 009-变态跳台阶

    • 010-矩形覆盖

  • 搜索算法

    • 001-二维数组查找

    • 006-旋转数组的最小数字(二分查找)

    • 037-数字在排序数组中出现的次数(二分查找)

  • 全排列

    • 027-字符串的排列

  • 动态规划

    • 030-连续子数组的最大和

    • 052-正则表达式匹配(我用的暴力)

  • 回溯

    • 065-矩阵中的路径(BFS)

    • 066-机器人的运动范围(DFS)

  • 排序

    • 035-数组中的逆序对(归并排序)

    • 029-最小的K个数(堆排序)

    • 029-最小的K个数(快速排序)

  • 位运算

  • 其他算法

    • 002-替换空格

    • 013-调整数组顺序使奇数位于偶数前面

    • 028-数组中出现次数超过一半的数字

    • 031-整数中1出现的次数(从1到n整数中1出现的次数)

    • 032-把数组排成最小的数

    • 033-丑数

    • 041-和为S的连续正数序列(滑动窗口思想)

    • 042-和为S的两个数字(双指针思想)

    • 043-左旋转字符串(矩阵翻转)

    • 046-孩子们的游戏-圆圈中最后剩下的数(约瑟夫环)

    • 051-构建乘积数组

剑指offer刷题交流群

  扫码添加微信,一定要备注研究方向+地点+学校+昵称(如机器学习+上海+上交+汤姆),只有备注正确才可以加群噢。

 ▲长按加群

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值