2021-1

目录

栈... 5

20. 有效的括号(简单)... 5

32. 最长有效括号(困难)... 6

1209. 删除字符串中的所有相邻重复项 II(中等)... 7

71. 简化路径(中等)... 8

150. 逆波兰表达式求值(中等)... 9

单调栈... 11

42. 接雨水(困难)... 11

84. 柱状图中最大的矩形(困难)... 12

并查集... 15

滑动窗口(11道)... 15

剑指 Offer 42. 连续子数组的最大和(简单)... 15

209. 长度最小的子数组 (中等)... 16

1004. 最大连续1的个数 III(中等)... 16

1208. 尽可能使字符串相等(中等)... 18

239. 滑动窗口最大值(困难)... 19

3. 无重复字符的最长子串(中等)... 20

76. 最小覆盖子串(困难)... 21

567. 字符串的排列(中等)... 23

30. 串联所有单词的子串(困难)... 24

632. 最小区间(困难)... 27

1143. 最长公共子序列(中等)... 28

718. 最长重复子数组(中等)... 29

前缀和 & HASH.. 31

560. 和为K的子数组(中等)... 31

974. 和可被 K 整除的子数组(中等)... 32

差分... 33

1109. 航班预订统计... 33

1094. 拼车(中等)... 34

122. 买卖股票的最佳时机 II(简单)... 35

拓扑排序... 36

字符串... 36

387. 字符串中的第一个唯一字符(简单)... 36

451. 根据字符出现频率排序(中等)... 37

93. 复原IP地址(中等)... 38

227. 基本计算器 II(中等)... 40

1002. 查找常用字符(简单)... 41

43. 字符串相乘(中等)... 42

17. 电话号码的字母组合(中等)... 43

824. 山羊拉丁文(简单)... 47

二分查找... 48

贪心法... 48

452. 用最少数量的箭引爆气球(中等)... 48

392. 判断子序列(简单)... 49

455. 分发饼干(简单)... 50

1247. 交换字符使得字符串相同(中等)... 51

45. 跳跃游戏 II(困难)... 52

621. 任务调度器(中等)... 54

376. 摆动序列(中等)... 56

135. 分发糖果(困难)... 58

字典树... 60

820. 单词的压缩编码(中等)... 60

Trie树中最常见的两个能是键的插入和查找。... 61

208. 实现 Trie (前缀树) 64

DP. 65

5. 最长回文子串(中等)... 65

300. 最长上升子序列(中等)... 67

一维动态规划... 71

leetcode198打家劫舍... 72

入室抢劫2. 73

91. 解码方法(中等)... 73

53. 最大子序和... 74

152. 乘积最大子数组(中等)... 74

643. 子数组最大平均数 I 75

121. 买卖股票的最佳时机(简单)... 76

122. 买卖股票的最佳时机 II(简单)... 77

123. 买卖股票的最佳时机 III(困难)... 79

188. 买卖股票的最佳时机 IV(困难)... 81

309. 最佳买卖股票时机含冷冻期(中等)... 82

714. 买卖股票的最佳时机含手续费(中等)... 83

139. 单词拆分(中等)... 84

140. 单词拆分 II(困难)... 86

303. 区域和检索 - 数组不可变(简单)... 87

位运算... 88

338. 比特位计数(中等)... 88

链表... 89

142. 环形链表 II(链表中环的入口结点)... 89

143. 重排链表(中等)... 90

83. 删除排序链表中的重复元素(简单)... 91

21. 合并两个有序链表(简单)... 92

19. 删除链表的倒数第N个节点... 92

树... 93

101. 对称二叉树... 93

107. 二叉树的层次遍历 II 94

103. 二叉树的锯齿形层次遍历(中等)... 95

106. 从中序与后序遍历序列构造二叉树(中等)... 96

图... 98

200. 岛屿数量(中等)... 98

130. 被围绕的区域(中等)... 100

695. 岛屿的最大面积(中等)... 103

332. 重新安排行程(中等)... 106

面试题 04.01. 节点间通路... 108

1557. 可以到达所有点的最少点数目... 109

841. 钥匙和房间... 111

207. 课程表... 112

210. 课程表 II 114

630. 课程表 III(困难)... 115

1462. 课程安排 IV(中等)... 117

1162. 地图分析(中等)... 119

934. 最短的桥... 120

排序... 121

977. 有序数组的平方(简单)... 121

88. 合并两个有序数组(简单)... 122

986. 区间列表的交集(中等)... 124

56. 合并区间(中等)... 126

57. 插入区间(困难)... 127

435. 无重叠区间(中等)... 129

495. 提莫攻击(中等)... 130

其他... 131

697. 数组的度... 131

1122. 数组的相对排序... 132

459. 重复的子字符串... 132

763. 划分字母区间... 134

463. 岛屿的周长... 134

657. 机器人能否返回原点... 135

347. 前 K 个高频元素... 136

剑指 Offer 10- I. 斐波那契数列... 137

316. 去除重复字母(中等)... 137

406. 根据身高重建队列(中等)... 138

13. 罗马数字转整数(简单)... 139

58. 最后一个单词的长度(简单)... 141

443. 压缩字符串(中等)... 141

6. Z 字形变换(中等)... 143

26. 删除排序数组中的重复项(简单)... 144

1. 两数之和(简单)... 145

15. 三数之和(中等)... 145

31. 下一个排列(中等)... 147

933. 最近的请求次数(简单)... 148

136. 只出现一次的数字(简单)... 150

645. 错误的集合(简单)... 150

1680. 连接连续二进制数字(中等)... 151

155. 最小栈(简单)... 152

232. 用栈实现队列(简单)... 153

622. 设计循环队列(中等)... 155

225. 用队列实现栈(简单)... 158

KMP. 160

1392. 最长快乐前缀(困难)... 160

背包... 161

416. 分割等和子集(中等)... 161

698. 划分为k个相等的子集(中等)... 162

设计题... 164

1396. 设计地铁系统(中等)... 164

真题... 166

0925可信上机编程“路由表最长匹配”... 166

-. 166

0911可信上机编程“速记内容复原”... 170

1120可信上机编程“自动售货机进出货管理系统”... 172

目录结构字符串... 176

附录:... 178

sorted(courses, key=lambda x:x[1]) 179

courses.sort(key=lambda x: x[0]) 179

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

 

 

 

 

 

20. 有效的括号简单

给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。

左括号必须以正确的顺序闭合。

注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"

输出: true

示例 2:

输入: "()[]{}"

输出: true

示例 3:

输入: "(]"

输出: false

示例 4:

输入: "([)]"

输出: false

示例 5:

输入: "{[]}"

输出: true

解题思路:栈

算法原理

栈先入后出特点恰好与本题括号排序特点一致,即若遇到左括号入栈,遇到右括号时将对应栈顶左括号出栈,则遍历完所有括号后 stack 仍然为空;

建立哈希表 dic 构建左右括号对应关系:key左括号,value右括号;这样查询 2 个括号是否对应只需 O(1)时间复杂度;建立栈 stack,遍历字符串 s 并按照算法流程一一判断。

算法流程

(1)如果 c 是左括号,则入栈;

(2)如果 c 是右括号,通过哈希表判断括号对应关系,若 stack 栈顶出栈括号 stack.pop() 与当前遍历括号 c 不对应或着栈为空,则提前返回 false。

复杂度分析

时间复杂度 O(N):正确的括号组合需要遍历一遍 s;

空间复杂度 O(N):哈希表和栈使用线性的空间大小。

 

class Solution:

    def isValid(self, s: str) -> bool:

        if len(s) % 2 == 1:

            return False

        pairs = {

            ')''(',

            ']''[',

            '}''{',

        }

        stack = list()

        for ch in s:

            if ch in pairs:

                if not stack or stack[-1] != pairs[ch]:

                    return False

                stack.pop()

            else:

                stack.append(ch)

 

        return not stack

32. 最长有效括号(困难)

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1

输入:s = "(()"

输出:2

解释:最长有效括号子串是 "()"

示例 2

输入:s = ")()())"

输出:4

解释:最长有效括号子串是 "()()"

示例 3

输入:s = ""

输出:0

 

提示:

  • 0 <= s.length <= 3 * 104
  • s[i] 为 '(' 或 ')'

方法:栈

始终保持栈底元素为当前已经遍历过的元素中【最后一个没有被匹配的右括号的下标】,这主要是考虑了边界条件的处理,栈里其它元素维护左括号的下标:

  1. 对于遇到的每个‘(’,将它的下标放入栈中
  2. 对于遇到的每个‘)’,先弹出栈顶元素表示匹配了当前右括号:
  1. 如果栈为空,说明当前的右括号为没有被匹配的右括号,将其下标放入栈中来更新我们之前提到的【最后一个没有被匹配的右括号的下标】
  2. 如果栈不为空,当前右括号的下标减去栈顶元素即为【以该右括号为结尾的最长有效括号的长度】

class Solution:

    def longestValidParentheses(self, s: str) -> int:

        if not s:

            return 0

        res = 0

        stack = [-1]

        for i in range(len(s)):

            if s[i] == '(':

                stack.append(i)

            else:

                stack.pop()

                if not stack:

                    stack.append(i)

                else:

                    res = max(res, i-stack[-1])

        return res

1209. 删除字符串中的所有相邻重复项 II(中等)

给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。

你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。

在执行完所有删除操作后,返回最终得到的字符串。

本题答案保证唯一。

示例 1

输入:s = "abcd", k = 2

输出:"abcd"

解释:没有要删除的内容。

示例 2

输入:s = "deeedbbcccbdaa", k = 3

输出:"aa"

解释:

先删除 "eee" 和 "ccc",得到 "ddbbbdaa"

再删除 "bbb",得到 "dddaa"

最后删除 "ddd",得到 "aa"

示例 3

输入:s = "pbbcggttciiippooaais", k = 2

输出:"ps"

提示:

1 <= s.length <= 10^5

2 <= k <= 10^4

s 中只含有小写英文字母。

解题思路:

将元素依次入栈并统计元素数量。每次入栈判断是否和栈顶元素相同:

  1. 如果与栈顶元素相同,那么将栈顶元素的数量加 1;
  2. 如果栈顶元素数量达到 3,则将栈顶元素出栈;
  3. 如果待入栈元素与栈顶元素不同,那么直接入栈并将该元素个数置为 1。

遍历完字符串之后,将栈中剩余元素拼接即为答案。

 

class Solution:

    def removeDuplicates(self, s: str, k: int) -> str:

        stack = []

        for c in s:

            if not stack or stack[-1][0] != c:

                stack.append([c, 1])

            elif stack[-1][1] + 1 < k:

                stack[-1][1] += 1

            else:

                stack.pop()

        # ans = ""

        # for c, k in stack:

        #     ans += c*k

        return ("".join(c*k) for c, k in stack)

71. 简化路径(中等)

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

 

示例 1

输入:"/home/"

输出:"/home"

解释:注意,最后一个目录名后面没有斜杠。

示例 2

输入:"/../"

输出:"/"

解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。

示例 3

输入:"/home//foo/"

输出:"/home/foo"

解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。

示例 4

输入:"/a/./b/../../c/"

输出:"/c"

示例 5

输入:"/a/../../b/../c//.//"

输出:"/c"

示例 6

输入:"/a//bc/d//././/.."

输出:"/a/b/c"

方法:栈

class Solution:

    def simplifyPath(self, path: str) -> str:

        stack = []

        path = path.split('/')

        for item in path:

            if item == '..':

                if stack:

                    stack.pop()

            elif item and item != '.':

                stack.append(item)

        return "/" + "/".join(stack)

150. 逆波兰表达式求值(中等)

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。

给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1

输入: ["2", "1", "+", "3", "*"]

输出: 9

解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2

输入: ["4", "13", "5", "/", "+"]

输出: 6

解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3

输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]

输出: 22

解释:

该算式转化为常见的中缀算术表达式为:

  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5

= ((10 * (6 / (12 * -11))) + 17) + 5

= ((10 * (6 / -132)) + 17) + 5

= ((10 * 0) + 17) + 5

= (0 + 17) + 5

= 17 + 5

= 22

 

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。

方法:栈

遇到数字则入栈;
遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。

class Solution:

    def evalRPN(self, tokens: List[str]) -> int:

        stack = []

        for i, item in enumerate(tokens):

            if item in "+-*/":

                numb = stack.pop()

                numa = stack.pop()

                if item == '+':

                    stack.append(numa+numb)

                elif item == '-':

                    stack.append(numa-numb)

                elif item == '*':

                    stack.append(numa*numb)

                else:

                    stack.append(int(numa/numb))

            else:

                stack.append(int(item))

        return stack[-1]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值