码迷,mamicode.com
首页 > 其他好文 > 详细

Leetcode (213)| 打家劫舍 2

时间:2020-12-21 11:13:08      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:翻转   stack   奇数   排序   不能   实现   小数   1出现的次数   运动   

微信公众号: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
如果我一开始打算抢a,那么d我是够不着了,所以我只能从a,b,c里进行递归
如果我一开始不打算抢b,那么d是在我考虑的范围内,我从b,c,d里进行挑选

对于 n >=4,有两个选项:
抢第1个房子,去掉最后一个房子。
不抢第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)完全背包问题

数据结构类题目

  • LinkedList
  • 003-从尾到头打印链表
  • 014-链表中倒数第k个结点
  • 015-反转链表
  • 016-合并两个或k个有序链表
  • 025-复杂链表的复制
  • 036-两个链表的第一个公共结点
  • 055-链表中环的入口结点
  • 056-删除链表中重复的结点
  • Tree
  • 004-重建二叉树
  • 017-树的子结构
  • 018-二叉树的镜像
  • 022-从上往下打印二叉树
  • 023-二叉搜索树的后序遍历序列
  • 024-二叉树中和为某一值的路径
  • 026-二叉搜索树与双向链表
  • 038-二叉树的深度
  • 039-平衡二叉树
  • 057-二叉树的下一个结点
  • 058-对称的二叉树
  • 059-按之字形顺序打印二叉树
  • 060-把二叉树打印成多行
  • 061-序列化二叉树
  • 062-二叉搜索树的第k个结点
  • Stack & Queue
  • 005-用两个栈实现队列
  • 020-包含min函数的栈
  • 021-栈的压入、弹出序列
  • 044-翻转单词顺序列(栈)
  • 064-滑动窗口的最大值(双端队列)
  • Heap
  • 029-最小的K个数
  • Hash Table
  • 034-第一个只出现一次的字符
  • 065-矩阵中的路径(BFS)
  • 066-机器人的运动范围(DFS)
  • 具体算法类题目
  • 斐波那契数列
  • 007-斐波拉契数列
  • 008-跳台阶
  • 009-变态跳台阶
  • 010-矩形覆盖
  • 搜索算法
  • 001-二维数组查找
  • 006-旋转数组的最小数字(二分查找)
  • 037-数字在排序数组中出现的次数(二分查找)
  • 全排列
  • 027-字符串的排列
  • 动态规划
  • 030-连续子数组的最大和
  • 052-正则表达式匹配(我用的暴力)
  • 回溯
  • 065-矩阵中的路径(BFS)
  • 066-机器人的运动范围(DFS)
  • 排序
  • 035-数组中的逆序对(归并排序)
  • 029-最小的K个数(堆排序)
  • 029-最小的K个数(快速排序)
  • 位运算
  • 011-二进制中1的个数
  • 012-数值的整数次方
  • 040-数组中只出现一次的数字
  • 其他算法
  • 002-替换空格
  • 013-调整数组顺序使奇数位于偶数前面
  • 028-数组中出现次数超过一半的数字
  • 031-整数中1出现的次数(从1到n整数中1出现的次数)
  • 032-把数组排成最小的数
  • 033-丑数
  • 041-和为S的连续正数序列(滑动窗口思想)
  • 042-和为S的两个数字(双指针思想)
  • 043-左旋转字符串(矩阵翻转)
  • 046-孩子们的游戏-圆圈中最后剩下的数(约瑟夫环)
  • 051-构建乘积数组

剑指offer刷题交流群

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

技术图片
▲长按加群

技术图片

Leetcode (213)| 打家劫舍 2

标签:翻转   stack   奇数   排序   不能   实现   小数   1出现的次数   运动   

原文地址:https://blog.51cto.com/15054042/2564540

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!