力扣面试经典150 —— 6-10题

news2024/11/18 19:50:35
  • 力扣面试经典150题
  • 在 VScode 中安装 LeetCode 插件即可使用 VScode 刷题,安装 Debug LeetCode 插件可以免费 debug
  • 本文使用 python 语言解题,文中 “数组” 通常指 python 列表;文中 “指针” 通常指 python 列表索引

文章目录

  • 6. [中等] 轮转数组
    • 6.1 解法1:使用额外的数组
    • 6.2 解法2:数组翻转
  • 7. [简单] 买卖股票的最佳时机
    • 7.1 解法1:暴力法
    • 7.2 解法2:贪心
  • 8. [中等] 买卖股票的最佳时机II
    • 8.1 解法1:贪心
    • 8.2 解法2:动态规划
  • 9. [中等] 跳跃游戏
    • 9.1 解法1:贪心模拟
    • 9.2 解法2:贪心
  • 10. [中等] 跳跃游戏II
    • 10.1 解法1:贪心模拟

6. [中等] 轮转数组

  • 题目链接
  • 标签:数组、数学、双指针
    在这里插入图片描述

6.1 解法1:使用额外的数组

  • 借助一个额外数据将各个元素放到新位置。注意到从整体上看,输出数组可以看作是在 k % len(nums) 位置截断然后重新组合,可以用 python 的列表操作简单地如下实现
    class Solution:
        def rotate(self, nums: List[int], k: int) -> None:
            k = k % len(nums)
            res = nums[-k:] + nums[:-k]
            nums[:] = res
    
    这其实等价于用两个指针分别遍历截断的两部分,并将元素依次复制到辅助数组
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

6.2 解法2:数组翻转

  • 和方法一一样,注意到输出数组可以看作是在 k % len(nums) 位置截断然后重新组合,这可以通过三次列表翻转实现,示意如下
    nums = "----->-->"; k =3
    result = "-->----->";
    
    reverse "----->-->" we can get "<--<-----"
    reverse "<--" we can get "--><-----"
    reverse "<-----" we can get "-->----->"
    
    下面给出代码,使用双指针进行翻转操作
    class Solution:
        def rotate(self, nums: List[int], k: int) -> None:
            def _reverse(start, end):
                while start < end:
                    t = nums[start]
                    nums[start] = nums[end]
                    nums[end] = t
                    start += 1
                    end -= 1
    
            k = k % len(nums)
            _reverse(0, len(nums)-1)
            _reverse(0, k-1)
            _reverse(k, len(nums)-1)
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

7. [简单] 买卖股票的最佳时机

  • 题目链接
  • 标签:数组、动态规划
    在这里插入图片描述

7.1 解法1:暴力法

  • 直接遍历所有可能的买卖组合情况,但这种方法会超时
    def maxProfit(self, prices: List[int]) -> int:
            # 暴力法:超时
            profit = -float('inf')
            for i in range(len(prices)-1):
                buy = prices[i]
                for j in range(i+1, len(prices)):
                    sell = prices[j]
                    if sell > buy and sell - buy > profit:
                        profit = sell - buy
            profit = 0 if profit < 0 else profit
            return profit
    
  • 时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( 1 ) O(1) O(1)

7.2 解法2:贪心

  • 只遍历一遍,在每个时刻贪心地计算可能的最大利润。为此,需要动态地更新截止目前为止的最低买入价
    class Solution:
        def maxProfit(self, prices: List[int]) -> int:
            # 贪心:动态维护历史最低价,进而利用它计算理论最大收益
            min_price = float('inf')
            max_profit = -float('inf')
            for p in prices:
                # 动态维护历史最低价
                if p < min_price:
                    min_price = p
    
                # 基于历史最低价得到在当前时刻卖出的理论最大收益
                profit = p - min_price
                if profit > max_profit:
                    max_profit = profit
    
            max_profit = 0 if max_profit < 0 else max_profit
            return max_profit
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

8. [中等] 买卖股票的最佳时机II

  • 题目链接
  • 标签:贪心、数组、动态规划
    在这里插入图片描述

8.1 解法1:贪心

  • 基于贪心的思想,实现最大利润意味着每一次可能的盈利都被把握。我们变量把股价曲线折线图,在每一个时刻执行收益最大化操作,即把每一个上升段都加入总收益中,水平或下降段则跳过
    class Solution:
        def maxProfit(self, prices: List[int]) -> int:
            max_profit = 0
            for i in range(len(prices)-1):
                profit = prices[i+1] - prices[i]
                if profit > 0:
                    max_profit += profit
            return max_profit
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

8.2 解法2:动态规划

  • 题目设置满足动态规划的三要素
    1. 无后效性:当前和未来的交易操作不会影响过去交易操作的收益
    2. 最优子结构:在整个交易过程中实现最大收益,意味着交易过程中的任意一个时间段的收益都是最优的。问题最优解的结构包含其子问题的最优解
    3. 重叠子问题:当我们递归地自顶向下分解时,即把 “最大化前n天收益” 不断地递归分解为 “最大化前n-1天收益,同时最大化第n-1天收益” 时,出现了要在递归过程中重复求解的重叠子问题(比如 “最大化前1天收益”),这提示我们使用递推式自底向上的构造解(动态规划的自底向上形式),或使用带备忘录的递归法(动态规划的自顶向下形式)
  • 我们使用自底向上的动态规划形式,这时需要构造递推公式(动态规划中称 “状态转移方程”)。定义状态 dp[i][0]dp[i][1] 分别表示第 i i i 天交易完后手里没有和持有股票的最大利润。
    1. 对于 dp[i][0] 来说,第 i i i 天交易完后手里没有股票,意味着要么前一天就没有,要么今天卖了,递推式为
      d p [ i ] [ 0 ] = max ⁡ { d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + p r i c e s [ i ] } dp[i][0]=\max\{dp[i−1][0],dp[i−1][1]+prices[i]\} dp[i][0]=max{dp[i1][0],dp[i1][1]+prices[i]}
    2. 对于 dp[i][1] 来说,第 i i i 天交易完后手里有股票,意味着要么前一天有,要么今天刚买,递推式为
      d p [ i ] [ 1 ] = max ⁡ { d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] − p r i c e s [ i ] } dp[i][1]=\max\{dp[i−1][1],dp[i−1][0]−prices[i]\} dp[i][1]=max{dp[i1][1],dp[i1][0]prices[i]}
    3. 根据问题定义,第0天交易时有
      d p [ 0 ] [ 0 ] = 0 , d p [ 0 ] [ 1 ] = − p r i c e s [ 0 ] dp[0][0]=0,\quad dp[0][1]=−prices[0] dp[0][0]=0,dp[0][1]=prices[0]
    4. 由于全部交易结束后,持有股票的收益一定低于不持有股票的收益,最后返回 d p [ n − 1 ] [ 0 ] dp[n−1][0] dp[n1][0] 即可
  • 注意到以上状态转移方程1、2中,dp[i] 仅与 dp[i-1] 有关,而与更早的状态都无关,因此不必存储这些无关的状态,只需要将 dp[i−1][0]dp[i−1][1] 存放在两个变量中,通过它们计算出 dp[i][0]dp[i][1] 并存回对应的变量,以便于第 i + 1 i+1 i+1 天的状态转移计算即可
    class Solution:
        def maxProfit(self, prices: List[int]) -> int:
            dp0 = 0             # 今日交易完后手里没有股票的最大利润
            dp1 = -prices[0]    # 今日交易完后手里有一支股票的最大利润
            for i in range(1, len(prices)):
                dp0_ = max(dp0, dp1 + prices[i])
                dp1_ = max(dp1, dp0 - prices[i])
                dp0, dp1 = dp0_, dp1_            
            return dp0
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

9. [中等] 跳跃游戏

  • 题目链接
  • 标签:贪心、数组、动态规划
    在这里插入图片描述

9.1 解法1:贪心模拟

  • 直接模拟整个转移过程,每次都贪心地跳到能去向的最远处,直到达到终点或无法前进
    class Solution:
        def canJump(self, nums: List[int]) -> bool:
            cur_pos = next_pos = 0
            max_range = nums[cur_pos]   # 当前可达的最大索引位置
            while True:
                # 若从当前位置可以直接到目标,退出
                if max_range >= len(nums) - 1:
                    return True
    
                # 考察从当前位置可达的每个新位置可覆盖的最大范围, 贪心地选择可达范围最大处作为转移到的索引位置 next_pos
                for steps in range(1, nums[cur_pos] + 1):
                    next_range = cur_pos + steps + nums[cur_pos + steps]
                    if next_range > max_range:
                        next_pos = cur_pos + steps
                        max_range = next_range
                
                # 如果当前位置已经是最佳的,且已知当前 max_range 无法到达目标,退出
                if next_pos == cur_pos:
                    return False
    
                # 去向新索引位置
                cur_pos = next_pos
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

9.2 解法2:贪心

  • 对于每一个可达位置 x x x,它使得 x + 1 , x + 2 , ⋯   , x + nums [ x ] x+1,x+2,⋯ ,x+\text{nums}[x] x+1,x+2,,x+nums[x] 这些连续的位置都可以到达。利用贪心的思想,我们遍历数组,并在每一步维护当前可达的最大状态,如果发现最后的位置可达则返回 true,反之若遍历结束后最后位置仍不可达则返回 false
    class Solution:
        def canJump(self, nums: List[int]) -> bool:
            max_range = 0
            for i, step in enumerate(nums):
                if i <= max_range:
                    if i + step > max_range:
                        max_range = i + step
                    if max_range >= len(nums) - 1:
                        return True
            return False
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

10. [中等] 跳跃游戏II

  • 题目链接
  • 标签:贪心、数组、动态规划
    在这里插入图片描述

10.1 解法1:贪心模拟

  • 和 9.1 完全一直,直接模拟整个转移过程,每次都贪心地跳到能去向的最远处,直到达到终点或无法前进。模拟的同时记录总跳跃次数并返回
    class Solution:
        def jump(self, nums: List[int]) -> int:
            # 特殊情况直接退出
            if len(nums) == 1:
                return 0
    
            cur_pos = next_pos = step_cnt = 0
            max_range = nums[cur_pos]
            while True:
                # 若从当前位置可以直接到目标,退出
                if max_range >= len(nums) - 1:
                    return step_cnt + 1
    
                # 考察每一个新位置可以覆盖的最大范围,next_pos 设置为范围最大新索引位置
                for steps in range(1, nums[cur_pos] + 1):
                    next_range = cur_pos + steps + nums[cur_pos + steps]
                    if next_range > max_range:
                        next_pos = cur_pos + steps
                        max_range = next_range
    
                # 去向新索引位置
                cur_pos = next_pos
                step_cnt += 1
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

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

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

相关文章

Qt/C++音视频开发68-检查是否含有B帧/转码推流/拉流显示/监控拉流推流/海康大华宇视监控

一、前言 为什么需要判断视频文件是否含有B帧&#xff0c;这个在推流的时候很容易遇到这个问题&#xff0c;一般来说&#xff0c;没有B帧的视频文件&#xff0c;解码后的数据帧pts和dts都是顺序递增的&#xff0c;而有B帧的则未必&#xff0c;可能有些需要先解码后面显示&…

CentOS上安装MySQL 5.7和MySQL 8.0教程

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

全天候购药系统(微信小程序+web后台管理)

PurchaseApplet 全天候购药系统&#xff08;微信小程序web后台管理&#xff09; 传统线下购药方式存在无法全天候向用户提供购药服务&#xff0c;无法随时提供诊疗服务等问题。为此&#xff0c;运用软件工程开发规范&#xff0c;充分调研建立需求模型&#xff0c;编写开发文档…

智慧城市的前景:数字孪生技术在智慧城市中的应用前景

目录 一、引言 二、数字孪生技术及其在智慧城市中的应用概述 三、数字孪生技术在智慧城市中的应用前景 1、城市规划与仿真模拟 2、智能交通与出行服务 3、智慧环保与可持续发展 4、智慧公共服务与社会治理 5、智慧能源与绿色建筑 四、数字孪生技术在智慧城市中的挑战与…

稀疏数组实现

博文主要是自己学习的笔记&#xff0c;供自己以后复习使用&#xff0c; 参考的主要教程是B站的 尚硅谷数据结构和算法 稀疏数组(sparse array) 实际需求&#xff1a;五子棋程序中的存盘退出和续上盘的功能 问题分析&#xff1a; 如果直接用二维数组&#xff0c;很多值是默认…

hfish蜜罐搭建与使用

本次是对自己在学习蓝队过程中的一次对安全设备 hfish蜜罐的搭建和使用考核记录,距离之前已 经过去很久了,对之前在考核过程中的操作进行回顾和总结. 蜜罐在这里我进行免费分享 hfish-3.1.4-windows-amd64.zip官方版下载丨最新版下载丨绿色版下载丨APP下载-123云…

Java工作需求后端代码--实现树形结构

加油&#xff0c;新时代打工人&#xff01; 前端页面 带树形结构的表格 最近在新项目上加班加点&#xff0c;下面是个实现树形结构的数据表格。 需求&#xff1a; 在前端页面表格中展示成树形结构的数据。 技术&#xff1a; 后端&#xff1a;Java、Mybatis-Plus、HuTool树形的…

回南天的解决方案

广东的回南天还是那么湿&#xff0c;各种短视频在秀。 墙上流水 楼顶滴水 厕所镜子看不到人 出门滑行 衣服永远是湿的 湿度100%&#xff01; 那么这个让人难受的回南天&#xff0c;除关门关窗&#xff0c;还有没有更好的解决方案&#xff1f;&#xff1f;&#xff08;小…

ChatGPT提示技巧——零,一和少量示例提示

ChatGPT提示技巧——零&#xff0c;一和少量示例提示 ​ 零样本(zero-shot)、少样本(few-shot)和单样本(one-shot)提示是用于在最少或没有示例的情况下从ChatGPT生成文本的技巧。这些技巧用于当某个具体任务有限定数据的时候或者任务是新的并且没有很好的定义的时候。 提示格…

[HackMyVM]靶场 Run

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

libevent源码解析:io事件(一)

文章目录 前言一、用例简单服务端实现参数设置 二、基本数据结构介绍三、源码分析event_base_newevent_newevent_addevent_base_dispatch 三、libevent和epoll中的事件标记epoll中的事件标记libevent中的事件标记libevent和epoll中事件标记的对应关系 总结 前言 libevent中对三…

libevent源码解析:定时器事件(三)

文章目录 前言一、用例小根堆管理定时器事件小根堆和链表管理定时器事件区别 二、基本数据结构介绍结构体成员分析小根堆和链表common_timeout图示 三、源码分析小根堆管理定时器事件event_newevent_addevent_dispatch 链表common_timeout管理定时器事件event_base_init_common…

react 分步表单中使用useEffect来更新表单值的问题

问题背景&#xff1a;我在完成一个分步表单的功能的时候&#xff0c;在进行点击下一步的时候&#xff0c;会通过useEffect 来监听下一步或者上一步的动作&#xff0c;进行表单赋值&#xff0c;我使用 useEffect(() > {setFieldsValue(formValues);}, [stepNum]) 直接赋值的…

动态规划:Leetcode 91.解码方法

题目 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; A -> "1" B -> "2" ... Z -> "26" 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可能有多种方法&am…

【Web安全】XSS攻击与绕过

【Web安全】XSS攻击与绕过 【Web安全靶场】xss-labs-master 1-20 文章目录 【Web安全】XSS攻击与绕过1. XSS攻击是啥&#xff1f;2. XSS如何发生&#xff1f;3. XSS分类3.1. 反射型3.2. 存储型3.3. DOM型 4. XSS攻击方式1. script标签2. img标签3. input标签4. details标签5.…

【IC设计】Windows和Ubuntu下安装Verilator

文章目录 Windows下安装verilatorUbuntu下安装verilator安装前的准备安装verilator检查 Windows下安装verilator windows下安装比较麻烦&#xff0c;需要首先安装cygwin&#xff0c;cygwin是一个包管理工具&#xff0c;类似apt&#xff0c;然后通过cygwin安装verilator所需的各…

『大模型笔记』LLM框架(LangChain、LlamaIndex、Haystack、Hugging Face)哪一个是满足您特定需求的最佳选择?

LLM框架(LangChain、LlamaIndex、Haystack、Hugging Face)哪一个是满足您特定需求的最佳选择&#xff1f; 文章目录 1. LangChain1.1. 优势1.2. 劣势1.1. 理想用例 2. LlamaIndex2.1. 优势2.2. 劣势2.3. 理想用例 3. Haystack3.1. 优势3.2. 劣势3.3. 理想用例 4. Hugging Face…

CSAPP-程序的机器级表示

文章目录 概念扫盲思想理解经典好图安全事件 概念扫盲 1.汇编代码使用文本格式&#xff0c;相较于汇编的二进制可读性更好 2.程序内存包括&#xff1a;可执行的机器代码、操作系统需要的信息、管理过程调用和返回的运行时栈、用户分配的内存块 3.链接器为函数调用找到匹配的可…

ffmpeg maxrate 导致转码输出的内容包含随机性

https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate 问题 领导提出了一个问题&#xff0c;为什么转码后的视频大小字节数据都不一样&#xff0c;这问到我了&#xff0c;一时语塞。查一下吧&#xff0c;没有什么资料支撑。主动试一下。 尝试 首先尝试一下直接…

JVM-对象创建与内存分配机制深度剖析 3

JVM对象创建过程详解 类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个 符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类加载过程。 new…