备战秋招60天算法挑战,Day32

news2024/9/20 16:34:05

题目链接: https://leetcode.cn/problems/house-robber-ii/

视频题解: https://www.bilibili.com/video/BV1WRYKeKEQE/

LeetCode 213. 打家劫舍 II

题目描述

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

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

举个例子:

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

视频题解

打家劫舍 II

思路来源

思路来源

知识回顾

动态规划是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于求解最优化问题,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解推导出原问题的最优解。可以通过两点来判断一个问题能不能通过动态规划来解,一是该问题是否存在递归结构,二是对应的子问题能否记忆化。动态规划可以通过带备忘录的自上而下的递归自下而上的迭代来分别实现。由于递归需要用到栈来实现,一些语言对递归的深度是有限制的,所以自下而上的迭代是动态规划的最佳实现方式

思路解析

本题是一道经典的动态规划问题,要找到解决动态规划问题的两个突破点:推导出状态转移公式边界条件处理

本题是「198.打家劫舍」的进阶版,他们之间唯一的区别是房子变成了首尾相连,因为第1间房第n间房相连,我们需要考虑要不要偷第1间房

  1. 如果偷第1间房,那么第n间房一定不能偷。这个时候我们可以偷的区间就变成[0,n-1]
  2. 如果不偷第1间房,那么我们可以偷的区间就变成[1,n]

最终就变成了求[0,n-1][1,n]这两个非首尾相连区间能够偷窃到的最高金额,这样就可以复用「198.打家劫舍」的思路。

首先定义dp[n]表示总共有n间房所能偷到的最高金额。

对于非首尾相连的数组nums=[1, 2, 3, 1]其所以可能的打劫路线如下:

根节点到叶子节点就是一条偷盗路线,每个节点表示偷到的总金额,对于上面的例子dp[4] = 4

状态转移公式需要分两种情况讨论:

  • 偷盗路线包含第4间房nums[3]),根据规则这个时候第3间房nums[2])一定是没有被偷的,那么前2间房偷到的最大金额加上第4间房偷到的金额有可能是前4间房偷的最大金额dp[4] = dp[2] + nums[3]
  • 偷盗路线不包含第4间房nums[3]),这个时候前3间房偷到的最大金额有可能也是前4间房偷的最大金额dp[4] = dp[3]

上面两种情况选取最大值就可以得到4间房偷到的最大金额dp[4]=max(dp[2] + nums[3], dp[3]);

扩展到一般情况dp[n]可以分解为dp[n-1]dp[n-2]两个子问题的组合,得到状态转移公式

dp[n] = max{dp[n-2] + nums[n-1], dp[n-1]}

其中dp[n-2] + nums[n-1]表示偷第n间房整条路线可以偷到的最大金额。 dp[n-1]表示不偷第n间房整条路线可以偷到的最大金额。

对于边界条件 dp[0] = 0dp[1] = nums[0]dp[2] = max{nums[0], nums[1]}

C++ 代码

class Solution {
public:
    int rob(vector<int>& nums) {
        int nums_len = nums.size();
        if (nums_len == 0) return 0;
        if (nums_len == 1) return nums[0];
        return max(help(nums, 0, nums_len - 1), help(nums, 1, nums_len - 1));
    }
    int help(vector<int>& nums, int start, int len) {
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return nums[start];
        }
        vector<int> dp(len + 1, 0);
        //边界条件
        dp[1] = nums[start];
        dp[2] = max(nums[start], nums[start + 1]);

        for (int i = start + 3; i < start + len + 1; ++i) {
              //状态转移公式
            dp[i - start] = max(dp[i - start - 1], dp[i - start - 2] + nums[i - 1]);
        }
        return dp[len];
    }
};

java代码

class Solution {
    public int rob(int[] nums) {
        int nums_len = nums.length;
        if (nums_len == 0) return 0;
        if (nums_len == 1) return nums[0];
        return Math.max(help(nums, 0, nums_len - 1), help(nums, 1, nums_len - 1));
    }

    public int help(int[] nums, int start, int len) {
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return nums[start];
        }
        int[] dp = new int[len + 1];
        // 边界条件
        dp[1] = nums[start];
        dp[2] = Math.max(nums[start], nums[start + 1]);

        for (int i = start + 3; i < start + len + 1; ++i) {
            // 状态转移公式
            dp[i - start] = Math.max(dp[i - start - 1], dp[i - start - 2] + nums[i - 1]);
        }
        return dp[len];
    }
}

python代码

class Solution:
    def rob(self, nums: List[int]) -> int:
        nums_len = len(nums)
        if nums_len == 0:
            return 0
        if nums_len == 1:
            return nums[0]
        return max(self.help(nums, 0, nums_len - 1), self.help(nums, 1, nums_len - 1))
    
    def help(self, nums: List[int], start: int, length: int) -> int:
        if length == 0:
            return 0
        if length == 1:
            return nums[start]
        dp = [0] * (length + 1)
        # 边界条件
        dp[1] = nums[start]
        dp[2] = max(nums[start], nums[start + 1])

        for i in range(start + 3, start + length + 1):
            # 状态转移公式
            dp[i - start] = max(dp[i - start - 1], dp[i - start - 2] + nums[i - 1])
        
        return dp[length]

复杂度分析

时间复杂度: 只需要遍历两遍数组nums,所以时间复杂度为O(n)nnums的长度。

空间复杂度: 需要借助一个dp数组,空间复杂度为O(n)nnums的长度。

实现优化

上面的空间复杂度是O(n),其实根据状态转移公式的特点,当前的状态只依赖前面的两个状态,我们可以不使用数组保存所有的状态,使用两个整型变量prenext来实现help函数。

c++代码

class Solution {
public:
    int rob(vector<int>& nums) {
        int nums_len = nums.size();
        if (nums_len == 0) return 0;
        if (nums_len == 1) return nums[0];
        return max(help(nums, 0, nums_len - 1), help(nums, 1, nums_len - 1));

    }

    int help(vector<int>& nums, int start, int len) {
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return nums[start];
        }
        //边界条件
        int pre = nums[start];
        int next = max(nums[start], nums[start + 1]);

        for (int i = start + 2; i < start + len; ++i) {
            //状态转移公式
            int temp = next; 
            next = max(pre + nums[i], next);
            pre = temp;
        }
        return next;
    }
};

java代码

class Solution {
    public int rob(int[] nums) {
        int nums_len = nums.length;
        if (nums_len == 0) return 0;
        if (nums_len == 1) return nums[0];
        return Math.max(help(nums, 0, nums_len - 1), help(nums, 1, nums_len - 1));
    }
    public int help(int[] nums, int start, int len) {
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return nums[start];
        }
        // 边界条件
        int pre = nums[start];
        int next = Math.max(nums[start], nums[start + 1]);

        for (int i = start + 2; i < start + len; ++i) {
            // 状态转移公式
            int temp = next;
            next = Math.max(pre + nums[i], next);
            pre = temp;
        }
        return next;
    }
}

python代码

class Solution:
    def rob(self, nums: List[int]) -> int:
        nums_len = len(nums)
        if nums_len == 0:
            return 0
        if nums_len == 1:
            return nums[0]
        return max(self.help(nums, 0, nums_len - 1), self.help(nums, 1, nums_len - 1))
    
    def help(self, nums: List[int], start: int, length: int) -> int:
        if length == 0:
            return 0
        if length == 1:
            return nums[start]
        # 边界条件
        pre = nums[start]
        next = max(nums[start], nums[start + 1])

        for i in range(start + 2, start + length):
            # 状态转移公式
            temp = next
            next = max(pre + nums[i], next)
            pre = temp
        
        return next

优化后复杂度分析

时间复杂度: 只需要遍历两遍数组nums,所以时间复杂度为O(n)nnums的长度。

空间复杂度: 只借助了几个整型变量,空间复杂度为O(1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2107788.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

京东的AIGC革新之旅:通过JoyCoder实现研发提效 | 新程序员

【导读】从需求分析、设计编码到测试运维&#xff0c;AI已经逐步渗透到软件开发的各个环节&#xff0c;如何切实针对研发场景进行提效&#xff0c;是业内每个企业都在思考的问题。本文作者详细分析了AI在研发中的实际应用&#xff0c;并分享了JoyCoder与京东内部工具结合的实际…

一款可以替代Notepad++的免费高级文本编辑器

Kate 文本编辑器是一款跨平台的免费高级文本编辑器&#xff0c;具有丰富的功能和特性。它支持标签页、代码高亮、多文件查找、垂直/水平视图、侧边栏、颜色主题等特性&#xff0c;类似于Notepad。它以其多功能性和易用性广受好评。Kate 支持多文档界面&#xff08;MDI&#xff…

加密技术.

基本保密通信模型 密码学发展 古典密码学 主要特点&#xff1a;数据的安全基于算法的保密 经典的加密⽅法包括凯撒密码&#xff08;Caesar Cipher&#xff09;&#xff08;替代密码&#xff09;、维吉尼亚密码&#xff08;Vigenre Cipher&#xff09; 主要分类 替代密码&…

OCR技术视角:智能文档管理中的票据自动化识别与处理

在数字化转型的浪潮中&#xff0c;企业对于高效、自动化的文档管理需求日益增长。票据作为企业运营中不可或缺的部分&#xff0c;其识别与管理的智能化成为了提升工作效率的关键。本文将深入探讨智能文档系统中票据识别功能的原理、技术优势以及在不同行业中的应用实践&#xf…

【报错已解决】`Solving environment: failed`

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言&#xff1a;一、问题描述&#xff1a;1.1 报错示例&#xff1a;1.2 报错分析&#xff1a;1.3 解决思路&#xff…

智能指针,QT,C++语言的关键字总结

八、C中关键字总结 1> C中一共有63个关键字&#xff0c;如上图所示&#xff0c;其中标红的为c语言中的关键字&#xff0c;有32个 2> 数据类型相关的关键字 bool、true、false&#xff1a;对于bool类型数据的相关处理&#xff0c;值为true和false char、wchar_t:char是…

《Exemplar Free Class Agnostic Counting》CVPR2022

概述 摘要&#xff1a; 这篇论文提出了一种新颖的“无范例类别无关计数”&#xff08;Exemplar Free Class Agnostic Counting&#xff09;方法&#xff0c;旨在测试时对新类别的对象进行计数&#xff0c;而无需访问该类别的标记训练数据。以往的类别无关计数方法无法在完全自…

【刷题笔记】打家劫舍问题

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 题目一 题目链接&#xff1a;打家劫舍I 思路 小偷每到一初&#xff0c;都可以选择对这个位置偷还是不偷&#xff0c;所以&#xff0c;这次我们需要定义两个表 小Tips&#xff1a;针对这种情况&#xff0c;一般…

OpenGL/GLUT实践:水面模拟——从单振源到 Gerstner Wave(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub&#xff1a;A-UESTCer-s-Code 文章目录 1 实现效果1 简单水面模拟——单振源1.1 水面高度函数1.2 水面建模1.3 openGL 渲染(1) renderSense(2) 其他 1.4 实现效果 2 添加鼠标控制3 添加纹理4 多个振源组合5 Gerstner Wave 模型5.1 原理5.2 具体实现5.2.1 全局变量…

pytest 常用的辅助函数和工具函数

pytest 常用的辅助函数和工具函数示例 # File: my_module.pydef fetch_data():return process datadef process_data():data fetch_data()return data.upper() import logging import sys import pytest#01-------------------------------pytest.fixture,sample_data 在测试…

Android 下的 XML 文件(概念理解、存储位置理解)

一、XML 1、XML 概述 XML&#xff08;Extensible Markup Language&#xff0c;可扩展标记语言&#xff09;是一种用于存储和传输数据的标记语言 类似于 HTML&#xff0c;但旨在传输和存储数据&#xff0c;而不是显示数据&#xff0c;且基本语法都是标签 2、XML 的特点 &am…

【2024数模国赛赛题思路公开】国赛B题思路丨附可运行代码丨无偿自提

2024年国赛B题解题思路 问题 1: 抽样检测方案设计 【题目分析】 分析&#xff1a; 目标是设计一个高效的抽样检测方案&#xff0c;在尽量少的样本数量下&#xff0c;确保在高信度水平下做出正确的接受或拒收决策。需要处理两个不同的信度要求&#xff0c;这对样本量的计算提…

解决matplotlib中文乱码最简单方案

解决matplotlib中文乱码问题方案众多&#xff0c;我认为如下方案是最简单的一个。 1、从电脑中搜索simhei字体&#xff0c;如下示意图是mac检索结果&#xff0c;或者直接搜索simhei.ttf下载字体 拷贝到指定路径&#xff1a;/path/to/mex/simhei.ttf 2、matplotlib 加载字体 …

【Git】本地仓库操作

Part1 基础概念 git作用&#xff1a;管理代码版本&#xff0c;记录&#xff0c;切换&#xff0c;合并代码 git仓库&#xff1a;记录文件状态内容和历史记录的地方&#xff08;.git文件夹&#xff09; git的三个区域&#xff1a;1&#xff09;工作区&#xff1a;实际开发时的文…

针对STM32串口输出乱码错误问题

STM32在通过printf打印到串口时出现的文字乱码问题 使用printf文件中main.c文件&#xff0c;检查文件的编码方式是否正确&#xff0c;如下图所示&#xff0c;选择Chinese GD2编码方式&#xff1a;Edit--》Configuration 检查串口输出还是乱码错误 可以检测所建文件夹中main.c…

大道至简,大厂官网基本都走简洁化设计路线。

「大道至简」是一种设计理念&#xff0c;强调设计应该追求简洁、直观、易用&#xff0c;而不是过多的修饰和繁琐的细节。 对于大厂的官网来说&#xff0c;简洁化设计路线的选择可能有以下几个原因&#xff1a; 1. 更好的用户体验&#xff1a; 简洁的设计可以让用户更容易地理…

【Python报错已解决】`EOFError: Ran out of input`

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言&#xff1a;一、问题描述&#xff1a;1.1 报错示例&#xff1a;1.2 报错分析&#xff1a;1.3 解决思路&#xff…

LM Studio 本地部署大模型Qwen

本人运行环境win11 、11th Gen Intel Core™ i7-11800H 2.30GHZ、NVIDIA GeForce RTX 3060 Laptop GPU LMStudio 运行环境要求 What are the minimum hardware / software requirements? Apple Silicon Mac (M1/M2/M3) with macOS 13.6 or newerWindows / Linux PC with a…

【区块链 + 人才服务】链节区块链教学管理平台 | FISCO BCOS应用案例

当前&#xff0c;政策支持和行业需求为“区块链 教育”的发展提供了机遇。政策方面&#xff0c;教育部于 2020 年发布了《高等学 校区块链技术创新行动计划》&#xff0c;提出到 2025 年&#xff0c;在高校布局建设一批区块链技术创新基地&#xff0c;培养汇聚一批区块 链技术…

打卡第五十七天:prim与kruskal算法

题目 一、prim 本题是最小生成树的模板题。最小生成树 可以使用 prim算法 也可以使用 kruskal算法计算出来。 最小生成树是所有节点的最小连通子图&#xff0c; 即&#xff1a;以最小的成本&#xff08;边的权值&#xff09;将图中所有节点链接到一起。 图中有n个节点&…