力扣面试经典150 —— 16-20题

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

文章目录

  • 16. [困难] 接雨水
    • 16.1 解法1:按行计算
    • 16.2 解法2:按列计算(动态规划)
    • 16.3 解法3:双指针
    • 16.4 解法4:栈
  • 17. [简单] 罗马数字转整数
    • 17.1 解法1:模拟所有组合情况
    • 17.2 解法2:根据规则模拟
  • 18. [中等] 整数转罗马数字
    • 18.1 解法1:枚举
    • 18.2 解法2:硬编码
  • 19. [简单] 最后一个单词的长度
    • 19.1 解法1:反向遍历
  • 20. [简单] 最长公共前缀
    • 20.1 解法1:纵向扫描

16. [困难] 接雨水

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

16.1 解法1:按行计算

  • 按列计算水量时,必须要考虑墙壁相对高度,这带来了一些困难。更简单的做法是分层计算水量,这样就不需要考虑墙壁的绝对高度,只要考虑当前位置是否有墙壁就行了。
  • 具体而言,对每一行水从左到右遍历,从找到第一个墙壁开始计数水量,到找到下一个墙壁时把水量累积起来
    class Solution:
        def trap(self, height: List[int]) -> int:
            water_sum = 0
            for h in range(max(height)):        # 按行考察
                water_cnt = 0
                get_left = False
                for i in range(len(height)):    # 考察行内墙壁的情况
                    if height[i] > h:           
                        # 当前位置被墙壁阻挡
                        if not get_left:
                            # 找到左侧墙壁,从此开始要计算水量        
                            get_left = True     
                        elif water_cnt > 0:
                            # 找到墙壁时已经有水,意味着找到右墙壁,累积水量
                            water_sum += water_cnt
                            water_cnt = 0
                    else:
                        # 当前位置无墙壁,若已经找到左墙则加一格水
                        if get_left:
                            water_cnt += 1
            return water_sum
    
  • 时间复杂度 O ( m ∗ n ) O(m*n) O(mn),其中 m m m 是最高墙壁高度;空间复杂度 O ( 1 ) O(1) O(1)。这个解法现在会超时了

16.2 解法2:按列计算(动态规划)

  • 如果最高墙壁高度很高,计算复杂度会到达 O ( n 2 ) O(n^2) O(n2) 导致超时。更好的方式是通过按列计算水量,将时间负责度降低到 O ( n ) O(n) O(n)。考察每一列水量的计算方法,其实只需要该列墙壁高度、该列左侧最高墙高度和该列右侧最高墙高度三个值即可
    在这里插入图片描述
    如上图所示,正在求的列水量为 max ⁡ ( 0 , min ⁡ ( leftMax , rightMax ) − height ) \max\big(0, \min(\text{leftMax},\text{rightMax})-\text{height}\big) max(0,min(leftMax,rightMax)height)

  • 基于以上想法,我们可以先统计每一个位置左右最高墙壁高度,再利用上式来计算水量。注意到计算当前位置左右最高墙壁高度是一个动态规划问题,因为其满足动态规划三要素

    1. 无后效性:当前找到的墙壁不影响之前找到的墙壁
    2. 最优子结构:我们最后要构造长 n n n 的最高墙壁高度列表,其中任意一段都是最高的,即问题最优解的结构包含其子问题的最优解。
    3. 重叠子问题:找第 i i i 个位置左侧的最高墙高度 = 找第 i − 1 i-1 i1 位置左侧最高墙高度,并取其和第 i i i 个位置墙壁高度的最大值。其中出现了自顶向下递归过程中要重复求解的重叠子问题,这提示我们使用递推式自底向上的构造解(动态规划的自底向上形式),或使用带备忘录的递归法(动态规划的自顶向下形式)

    我们通过以下动态规划递推式来高效计算每一个位置左右最高墙壁的高度
    leftMax [ i ] = max ⁡ ( leftMax [ i − 1 ] ,  height [ i ] ) 1 ≤ i ≤ n − 1 rightMax ⁡ [ i ] = max ⁡ ( rightMax ⁡ [ i + 1 ] ,  height [ i ] ) 0 ≤ i ≤ n − 2 \begin{aligned} &\text{leftMax} [i]=\max ( \text{leftMax} [i-1] , \space\text{height}[i]) && 1 \leq i \leq n-1\\ &\operatorname{rightMax}[i]=\max (\operatorname{rightMax}[i+1] , \space\text{height}[i]) &&0 \leq i \leq n-2 \end{aligned} leftMax[i]=max(leftMax[i1], height[i])rightMax[i]=max(rightMax[i+1], height[i])1in10in2

  • 下面给出代码

    def trap(self, height: List[int]) -> int:
    	# 通过动态规划递推式找出每个位置左右最高墙壁高度
    	n = len(height)
    	max_left = [0] * n
    	max_right = [0] * n
    	for i in range(1, n-1):
    	    max_left[i] = max(max_left[i-1], height[i-1])
    	for i in range(n-2, 0, -1):
    	    max_right[i] = max(max_right[i+1], height[i+1])
    	
    	# 基于每个位置左右最高墙壁高度中较低的那个,计算每一列的水量
    	water_sum = 0
    	for i in range(1, n-1):
    	    min_max_height = min(max_left[i], max_right[i])
    	    if min_max_height > height[i]:
    	        water_sum += min_max_height - height[i]
    	
    	return water_sum
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

16.3 解法3:双指针

  • 动态规划通常可以用双指针方法优化空间复杂度。本题中注意到 max_left[i]max_right[i] 都只用过一次,可以用 left, right 两个指针分别向中间移动,实时维护至此为止左右见过的最高墙壁高度 max_left, max_right 并计算列水量
    def trap(self, height: List[int]) -> int:
        # 核心在于找出每个位置左右最高墙壁高度中较低的那个
        left, right = 0, len(height) - 1
        max_left = max_right = 0
        water_sum = 0
        while left < right:
            # 用left,right两个指针分别向中间移动,实时维护至此为止左右见过的最高墙壁高度max_left, max_right
            max_left = max(max_left, height[left])
            max_right = max(max_right, height[right])
            
            # 直接根据左右最大高度判断
            if max_left < max_right:
                # 右边存在最高柱子 max_right 可以挡水,第 left 列存水量由 max_left 决定
                water_sum += max_left - height[left]
                left += 1
            else:
                # 左边存在最高柱子 max_left 可以挡水,第 right 列存水量由 max_right 决定
                water_sum += max_right - height[right]
                right -= 1
    
        return water_sum
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

16.4 解法4:栈

  • 另一种解此题的思路是:计算水量 -> 找每一行水的左右墙壁 -> 括号匹配,这样就可以用栈解决了
    在这里插入图片描述
  • 具体而言,我们使用基于栈符号匹配的思想找出每一对墙壁,同时计算水量
    1. 栈元素:位置索引
    2. 入栈时机:当前高度小于栈顶位置高度,说明找到了积水位置,入栈成为栈顶
    3. 出栈时机:当前高度大于栈顶位置高度,说明找到了栈顶位置的那水的右侧墙,不断出栈计算水量,直到当前高度不大于栈顶或栈空,再把当前位置入栈
    4. 栈底元素:还没有计算水量的部分的左侧最高墙壁位置
  • 下面给出代码
    def trap(self, height: List[int]) -> int:
    	water_sum = 0
    	stack = []  # 用列表充当栈,stack[0] 是栈底, stack[-1] 是栈顶
    	
    	for i, h in enumerate(height):
    	    # 栈非空,且当前位置高度 > 栈顶位置高度,一直出栈计算水量
    	    while len(stack) != 0 and h > height[stack[-1]]:
    	        # 弹出栈顶,计算此位置水所在的整行水量
    	        top = stack.pop()   
    	        if len(stack) == 0: # 弹出之后栈空了,说明弹出的是最左侧的墙,不计算水量直接跳出
    	            break
    	        
    	        # 目标行水左边最高墙位置和高度
    	        left = stack[-1]
    	        max_left = height[left]
    	
    	        # 目标行水宽度
    	        water_width = i - left - 1
    	
    	        # 计算目标行水量,求和
    	        water_height = min(max_left, height[i]) - height[top]
    	        water_sum += water_width * water_height
    	    
    	    stack.append(i)
    	return water_sum
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

17. [简单] 罗马数字转整数

  • 题目链接
  • 标签:哈希表、数学、字符串
    在这里插入图片描述

17.1 解法1:模拟所有组合情况

  • 注意到罗马数字规则是左结合的,一种简单的想法是列出题目范围内所有可能的罗马数字组合情况,然后从左到右遍历,识别各个罗马数字相加
    def romanToInt(self, s: str) -> int:
    	char2value = {
    	     'I': 1,
    	     'V': 5,
    	     'X': 10,
    	     'L': 50,
    	     'C': 100,
    	     'D': 500,
    	     'M': 1000,
    	     'IV': 4,
    	     'IX': 9,
    	     'XL': 40,
    	     'XC': 90,
    	     'CD': 400,
    	     'CM': 900
    	 }
    	
    	 i, value = 0, 0
    	 while True:
    	     if s[i:i+2] in char2value:
    	         value += char2value[s[i:i+2]]
    	         i += 2
    	     else:
    	         value += char2value[s[i:i+1]]
    	         i += 1
    	
    	     if i >= len(s):
    	         break
    	 
    	 return value
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

17.2 解法2:根据规则模拟

  • 仔细分析罗马数字的构造规则,注意到
    1. 通常情况下小的数字在大的数字的右边。若输入的字符串满足该情况,那么可以将每个字符视作一个单独的值,累加每个字符对应的数值即可
    2. 若存在小的数字在大的数字的左边的情况,根据规则需要减去小的数字。对于这种情况,我们也可以将每个字符视作一个单独的值,若一个数字右侧的数字比它大,则将该数字的符号取反
  • 给出代码如下
    def romanToInt(self, s: str) -> int:
    	char2value = {
    	    'I': 1,
    	    'V': 5,
    	    'X': 10,
    	    'L': 50,
    	    'C': 100,
    	    'D': 500,
    	    'M': 1000,
    	}
    	
    	l = len(s)
    	value = 0
    	for i in range(l):
    	    if i < l - 1 and char2value[s[i]] < char2value[s[i+1]]:
    	        value -= char2value[s[i]]
    	    else:
    	        value += char2value[s[i]]
    	
    	return value
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

18. [中等] 整数转罗马数字

  • 题目链接
  • 标签:哈希表、数学、字符串
    在这里插入图片描述

18.1 解法1:枚举

  • 分析罗马数字的构造规则,发现其在个十百千位的构成规则是一样的,取值可以分成五种情况
    1. 取值 “1,2,3”:直接重复对应次取值 “1” 的符号(I/X/C
    2. 取值 “4”:由取值 “5” 的符号加-1前缀构成(IV/XL/CD
    3. 取值 “5”:有特殊符号(V/L/D
    4. 取值 “6,7,8”:由取值 “5” 的符号加重复对应次取值 “1” 的符号构成
    5. 取值 “9”:由更高一位取值 “1” 的符号和-1前缀构成(IX/XC/CM
  • 可以先拆分个十百千位取值,然后通过以上枚举关系转换
    def intToRoman(self, num: int) -> str:
    	s = ''
    	
    	# 千位
    	thousands = num // 1000
    	s += 'M' * thousands
    	
    	# 百位
    	num -= thousands * 1000
    	hundreds = num // 100
    	if hundreds == 9:
    	    s += 'CM'
    	elif hundreds > 5:
    	    s += 'D' + 'C' * (hundreds-5)
    	elif hundreds == 5:
    	    s += 'D'
    	elif hundreds == 4:
    	    s += 'CD'
    	else:
    	    s += 'C' * hundreds
    	
    	# 十位
    	num -= hundreds * 100
    	tens = num // 10
    	if tens == 9:
    	    s += 'XC'
    	elif tens > 5:
    	    s += 'L' + 'X' * (tens-5)
    	elif tens == 5:
    	    s += 'L'
    	elif tens == 4:
    	    s += 'XL'
    	else:
    	    s += 'X' * tens
    	
    	# 个位
    	num -= tens * 10
    	ones = num
    	if ones == 9:
    	    s += 'IX'
    	elif ones > 5:
    	    s += 'V' + 'I' * (ones-5)
    	elif ones == 5:
    	    s += 'V'
    	elif ones == 4:
    	    s += 'IV'
    	else:
    	    s += 'I' * ones
    	
    	return s
    
  • 时间复杂度 O ( 1 ) O(1) O(1),空间复杂度 O ( 1 ) O(1) O(1)

18.2 解法2:硬编码

  • 以上枚举过程写起来比较麻烦,可以将其全部整理成如下硬编码表,然后直接根据各位数据取值组合出结果
    在这里插入图片描述
  • 代码如下
    class Solution:
    
        THOUSANDS = ["", "M", "MM", "MMM"]
        HUNDREDS = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]
        TENS = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]
        ONES = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
    
        def intToRoman(self, num: int) -> str:
            return Solution.THOUSANDS[num // 1000] + \
                Solution.HUNDREDS[num % 1000 // 100] + \
                Solution.TENS[num % 100 // 10] + \
                Solution.ONES[num % 10]
    
  • 时间复杂度 O ( 1 ) O(1) O(1),空间复杂度 O ( 1 ) O(1) O(1)

19. [简单] 最后一个单词的长度

  • 题目链接
  • 标签:字符串
    在这里插入图片描述

19.1 解法1:反向遍历

  • 虽然这个可以直接用python字符串的 split 语法切分,然后反向遍历找到最后一个单词,但作为算法题还是不用这些语法了。首先我们去除字符串最右边的空格,然后反向遍历计数至第一个空格即可
    def lengthOfLastWord(self, s: str) -> int:
        # 去掉最右边的空格
        right = len(s) - 1
        while s[right] == ' ':
            right -= 1
        s = s[:right+1]
        
        # 从后往前遍历直到出现空格或遍历完成,同时计数
        l = 0
        for i in range(len(s)-1,-1,-1):
            if s[i] != ' ':
                l += 1
            else:
                break
        
        return l    
    
  • 时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

20. [简单] 最长公共前缀

  • 题目链接
  • 标签:字典树、字符串
    在这里插入图片描述

20.1 解法1:纵向扫描

  • 遍历第一个字符串,同时检查其他每一个字符串前缀是否和第一个的相同,遇到不同时即返回
    在这里插入图片描述
  • 代码如下
    def longestCommonPrefix(self, strs: List[str]) -> str:
    	prefix = ''
    	for i in range(len(strs[0])):
    	    char = strs[0][i]
    	    for str in strs[1:]:
    	        if i >= len(str) or str[i] != char:
    	            return prefix
    	    prefix += char
    	    i += 1
    	return prefix
    
  • 时间复杂度 O ( m n ) O(mn) O(mn),其中 m m m 是字符串数组中的字符串的平均长度, n n n 是字符串的数量;空间复杂度 O ( 1 ) O(1) O(1)

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

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

相关文章

深度学习——第10章 优化神经网络:如何防止过拟合(DNN)

第10章 优化神经网络:如何防止过拟合(DNN) 目录 10.1 什么是过拟合 10.2 L1、L2正则化 10.3 L2正则化的物理解释 10.4 Dropout正则化 10.5 其它正则化技巧 10.6 总结 上一课,我们一步步搭建了一个深层神经网络来实现图片的分类。结果显示,随着网络层数加深,隐藏层数…

【力扣 - 合并区间】

题目描述 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [start_i, end_i] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;int…

剑指offer C ++双栈实现队列

1. 基础 队列&#xff1a;先进先出&#xff0c;即插入数据在队尾进行&#xff0c;删除数据在队头进行&#xff1b; 栈&#xff1a;后进先出&#xff0c;即插入与删除数据均在栈顶进行。 2. 思路 两个栈实现一个队列的思想&#xff1a;用pushStack栈作为push数据的栈&#xff…

Linux 多进程开发(下)

第二章 Linux 多进程开发 2.6 进程间通信2.6.1 匿名管道2.6.2 有名管道2.6.3 内存映射2.6.4 信号2.6.5 共享内存 2.7 守护进程 网络编程系列文章&#xff1a; 第1章 Linux系统编程入门&#xff08;上&#xff09; 第1章 Linux系统编程入门&#xff08;下&#xff09; 第2章 L…

word中图片位置问题(后续遇到问题再更新)

问题1&#xff1a;图片插入后显示不全 具体表现为&#xff1a;复制黏贴、或者插入图片后&#xff0c;出现插入的图片显示不全&#xff0c;或者不显示。 例如&#xff1a; 这是因为&#xff1a;图片被设定了固定行距 解决方案&#xff1a;ctrl1 效果&#xff1a; 问题2&am…

南昌云宸网络发展有限公司-小分类客户可自选

南昌云辰网络发展有限公司是华东地区最大的互联网公司。 公司业务涉及互联网营销策划、移动互联网、物联网、广告传媒、微电影、***等&#xff0c;依托以互联网技术为核心的B2B企业贸易平台和O2O电子商务平台&#xff0c;提供为用户提供一站式网络营销策划和解决方案。 &#…

String类(C++)详解与应用

1. 标准库中的string类 1.1 string类 http://www.cplusplus.com/reference/string/string/?kwstringhttp://www.cplusplus.com/reference/string/string/?kwstring1. 字符串是表示字符序列的类2. 标准的字符串类提供了对此类对象的支持&#xff0c;其接口类似于标准字符容器的…

【数据库】Oracle内存结构与参数调优

Oracle内存结构与参数调优 Oracle 内存结构概览oracle参数配置概览重要参数&#xff08;系统运行前配置&#xff09;:次要参数&#xff08;可在系统运行后再优化调整&#xff09;: Oracle数据库服务器参数如何调整OLTP内存分配操作系统核心参数配置Disabling ASMM&#xff08;禁…

力扣--课程表--bfs+dfs

整体思路&#xff1a; 这是一道拓扑序列的题目&#xff0c;我们将边的方向定义成从先修课指向后修课的方向&#xff0c;借一下官方的题解图片&#xff0c;我们需要判断的是形成的这个图结构是否存在环&#xff0c;如果存在环&#xff0c;那么代表不能完成所有课程的学习。 bfs思…

【leetcode】相同的树➕对称二叉树➕另一棵树的子树

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家刷题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 相同的树二. 对称二叉树三. 另一棵树的子树 一. 相同的树 点击查看题目 思路: bool isSameTree(…

YOLOv9改进 添加新型卷积注意力框架SegNext_Attention

一、SegNext论文 论文地址:2209.08575.pdf (arxiv.org) 二、 SegNext_Attention注意力框架结构 在SegNext_Attention中,注意力机制被引入到编码器和解码器之间的连接中,帮助模型更好地利用全局上下文信息。具体而言,注意力机制通过学习像素级的注意力权重,使得模型可以对…

ChatGPT Prompt 的原理总结

ChatGPT Prompt 的原理总结 ChatGPT Prompt 是 OpenAI 开发的大型语言模型 ChatGPT 的一种使用方式。通过 Prompt&#xff0c;用户可以引导 ChatGPT 生成特定内容&#xff0c;例如回答问题、写故事、写代码等等。 Prompt 的原理 Prompt 本质上是一段文本&#xff0c;它告诉 C…

Opencv 插值方法 总结

一、概括 面试的时候问到了一个图&#xff0c;就是如何将一个算子放缩&#xff1f;&#xff1f;我第一反应是resize&#xff08;&#xff09;,但是后来我转念一想&#xff0c;人家问的是插值方式&#xff0c;今天来总结一下 最邻近插值法原理分析及c实现_最临近插值法-CSDN博…

【位运算】【脑筋急转弯】2749. 得到整数零需要执行的最少操作数

作者推荐 视频算法专题 本文涉及知识点 2749. 得到整数零需要执行的最少操作数 给你两个整数&#xff1a;num1 和 num2 。 在一步操作中&#xff0c;你需要从范围 [0, 60] 中选出一个整数 i &#xff0c;并从 num1 减去 2i num2 。 请你计算&#xff0c;要想使 num1 等于 …

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的血细胞智能检测与计数(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;开发血细胞智能检测与计数系统对于疾病的预防、诊断和治疗具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个血细胞智能检测与计数系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&a…

oracle临时表空间不释放

项目报错 nested exception is java.sql.SQLException: ORA-01652: unable to extend temp segment by 128 in tablespace TEMP 原因是临时表空间满了&#xff0c;临时表空间一直增长&#xff0c;未释放导致临时表空间使用率100%。 查询临时表空间使用率 --临时表空间利用率…

Selenium控制已运行的Edge和Chrome浏览器(详细启动步骤和bug记录)

文章目录 前期准备1. 浏览器开启远程控制指令&#xff08;1&#xff09;Edge&#xff08;2&#xff09;Chrome 2. 执行python代码&#xff08;1&#xff09;先启动浏览器后执行代码&#xff08;2&#xff09;通过代码启动浏览器 3. 爬取效果3. 完整代码共享3.1 包含Excel部分的…

【Python爬虫神器揭秘】手把手教你安装配置Scrapy,高效抓取网络数据

1、 引言 在大数据时代&#xff0c;网络上的信息犹如海洋般浩瀚。想要在这片海洋里挖掘宝藏&#xff0c;一款强大的工具必不可少。今天我们要带大家深入探索的就是Python界鼎鼎大名的爬虫框架——Scrapy。无论你是数据分析师、研究员还是开发者&#xff0c;学会利用Scrapy来自…

力扣L7--- 7.整数反转(java版)--2024年3月12日

1.题目 2.知识点 注1&#xff1a; math.abs() 是一个 Java 中的数学函数&#xff0c;用于返回一个数的绝对值。例如&#xff0c;如果 x 的值是 -10&#xff0c;那么 Math.abs(x) 的值就是 10. 注2&#xff1a;Integer.MIN_VALUE-Math.pow(2,31)-1 Integer.MAX_VALUEMath.po…

VulnHub - Lampiao

希望和各位大佬一起学习&#xff0c;如果文章内容有错请多多指正&#xff0c;谢谢&#xff01; 个人博客链接&#xff1a;CH4SER的个人BLOG – Welcome To Ch4sers Blog Lampiao 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/lampiao-1,249/ 0x01 信息收集 Nm…