LeetCode 月报 202101
新年新气象,跑步逃离魔幻的 2020 年。
共计 30 题。充满并查集的一个月,已会默写。
605. 种花问题
题目
假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给定一个花坛(表示为一个数组包含 0
和 1
,其中 0
表示没种植花,1
表示种植了花),和一个数 n
。能否在不打破种植规则的情况下种入 n
朵花?能则返回 true
,不能则返回 false
。
示例
注意
- 数组内已种好的花不会违反种植规则;
- 输入的数组长度范围为
; n
是非负整数,且不会超过输入数组的大小。
题解
1250. 检查「好数组」
题目
给你一个正整数数组 nums
,你需要从中任选一些子集,然后将子集中每一个数乘以一个任意整数,并求出他们的和。
假如存在一种选取情况使该和结果为 1
,那么原数组就是一个「好数组」,则返回 true
;否则请返回 false
。
示例
提示
1 <= len(nums) <= 1e5
;1 <= nums[i] <= 1e9
。
题解
数学题。裴蜀定理的推广形式:若
239. 滑动窗口最大值
题目
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例
提示
1 <= len(nums) <= 1e5
;-1e4 <= nums[i] <= 1e4
;1 <= k <= len(nums)
。
题解
单调队列。
86. 分隔链表
题目
给你一个链表和一个特定值 x
,请你对链表进行分隔,使得所有小于 x
的节点都出现在大于或等于 x
的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例
题解
509. 斐波那契数
题目
斐波那契数,通常用
给你
示例
提示
0 <= n <= 30
。
题解
迭代
通项
查表
830. 较大分组的位置
题目
在一个由小写字母构成的字符串 s
中,包含由一些连续的相同字符所构成的分组。
例如,在字符串 s = "abbxxxxzyy"
中,就含有 "a"
、"bb"
、"xxxx"
、"z"
和 "yy"
这样的一些分组。
分组可以用区间 [begin, end]
表示,其中 begin
和 end
分别表示该分组的起始和终止位置的下标。上例中的 "xxxx"
分组用区间表示为 [3, 6]
。
我们称所有包含大于或等于三个连续字符的分组为较大分组。
找到每一个较大分组的区间,按起始位置下标递增顺序排序后,返回结果。
示例
提示
1 <= len(s) <= 1e3
;s
仅含小写英文字母。
题解
399. 除法求值
题目
给你一个变量对数组 equations
和一个实数值数组 values
作为已知条件,其中 equations[i] = [a_i, b_i]
和 values[i]
共同表示等式 a_i / b_i = values[i]
。每个 a_i
或 b_i
是一个表示单个变量的字符串。
另有一些以数组 queries
表示的问题,其中 queries[j] = [c_j, d_j]
表示第 j
个问题,请你根据已知条件找出 c_j / d_j
的结果作为答案。
返回所有问题的答案。如果存在某个无法确定的答案,则用 -1.0
替代这个答案。
注意
输入总是有效的。你可以假设除法运算中不会出现除数为 0
的情况,且不存在任何矛盾的结果。
示例
提示
1 <= len(equations) <= 20
;len(equations[i]) == 2
;1 <= len(a_i), len(b_i) <= 5
;len(values) == len(equations)
;0.0 < values[i] <= 20.0
;1 <= len(queries) <= 20
;len(queries[i]) == 2
;1 <= len(c_j), len(d_j) <= 5
;a_i
、b_i
、c_j
、d_j
由小写英文字母与数字组成。
题解
深度优先搜索
广度优先搜索
547. 省份数量
题目
有 n
个城市,其中一些彼此相连,另一些没有相连。如果城市 a
与城市 b
直接相连,且城市 b
与城市 c
直接相连,那么城市 a
与城市 c
间接相连。
省份是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 isConnected
,其中 isConnected[i][j] = 1
表示第 i
个城市和第 j
个城市直接相连,而 isConnected[i][j] = 0
表示二者不直接相连。
返回矩阵中省份的数量。
示例
题解
并查集
深度优先搜索
广度优先搜索
189. 旋转数组
题目
给定一个数组,将数组中的元素向右移动 k
个位置,其中 k
是非负数。
示例
说明
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题;
- 要求使用空间复杂度为
的原地算法。
题解
直接
分组
将数组划分为 gcd(n, k)
个模 k
循环组,其中 n = len(nums)
。
例如:n = 10
、k = 4
、p = gcd(n, k) = 2
。 此时只需 nums[0 -> 4 -> 8 -> 2 -> 6]
、nums[1 -> 5 -> 9 -> 3 -> 5]
即可完成旋转。
翻转
三次翻转。
123. 买卖股票的最佳时机 III
题目
给定一个数组,它的第 i
个元素是一支给定的股票在第 i
天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成两笔交易。
注意
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例
提示
1 <= len(prices) <= 1e5
;0 <= prices[i] <= 1e5
。
题解
通用
本题是“188. 买卖股票的最佳时机 IV”的特化,可直接套用。
特化
228. 汇总区间
题目
给定一个无重复元素的有序整数数组 nums
。
返回恰好覆盖数组中所有数字的最小有序区间范围列表。也就是说,nums
的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums
的数字 x
。
列表中的每个区间范围 [a, b]
应该按如下格式输出:
"a->b"
,如果a != b
;"a"
,如果a == b
。
示例
提示
0 <= len(nums) <= 20
;-2 ** 31 <= nums[i] <= 2 ** 31 - 1
;nums
中的所有值都互不相同;nums
按升序排列。
题解
1202. 交换字符串中的元素
题目
给你一个字符串 s
,以及该字符串中的一些「索引对」数组 pairs
,其中 pairs[i] = [a, b]
表示字符串中的两个索引(编号从 0
开始)。
你可以任意多次交换在 pairs
中任意一对索引处的字符。
返回在经过若干次交换后,s
可以变成的按字典序最小的字符串。
示例
提示
1 <= len(s) <= 1e5
;0 <= len(pairs) <= 1e5
;0 <= pairs[i][0], pairs[i][1] < len(s)
;s
中只含有小写英文字母。
题解
并查集。先求连通分支,再排序 s
的每个连通分支子序列。
1203. 项目管理
题目
公司共有 n
个项目和 m
个小组,每个项目要不无人接手,要不就由 m
个小组之一负责。
group[i]
表示第 i
个项目所属的小组,如果这个项目目前无人接手,那么 group[i]
就等于 -1
。(项目和小组都是从零开始编号的)小组可能存在没有接手任何项目的情况。
请你帮忙按要求安排这些项目的进度,并返回排序后的项目列表:
- 同一小组的项目,排序后在列表中彼此相邻;
- 项目之间存在一定的依赖关系,我们用一个列表
beforeItems
来表示,其中beforeItems[i]
表示在进行第i
个项目前(位于第i
个项目左侧)应该完成的所有项目。
如果存在多个解决方案,只需要返回其中任意一个即可。如果没有合适的解决方案,就请返回一个空列表。
示例
提示
1 <= m <= n <= 3e4
;len(group) == len(beforeItems) == n
0 <= len(beforeItems[i]) <= n - 1
;0 <= beforeItems[i][j] <= n - 1
i != beforeItems[i][j]
;-1 <= group[i] <= m - 1
;beforeItems[i]
不含重复元素。
题解
两次拓扑排序。
684. 冗余连接
题目
在本问题中,树指的是一个连通且无环的无向图。
输入一个图,该图由一个有着 N
个节点(节点值不重复)的树及一条附加的边构成。附加的边的两个顶点包含在 1
到 N
中间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组。每一个边的元素是一对 [u, v]
,满足 u < v
,表示连接顶点 u
和 v
的无向图的边。
返回一条可以删去的边,使得结果图是一个有着 N
个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v]
应满足相同的格式 u < v
。
示例
注意
- 输入的二维数组大小在
3
到1e3
; - 二维数组中的整数在
1
到N
之间,其中N
是输入数组的大小。
题解
并查集。
1018. 可被 5 整除的二进制前缀
题目
给定由若干 0
和 1
组成的数组 A
。我们定义 A[0]
到 A[i]
组成的第 i
个子数组被解释为一个二进制数(从最高有效位到最低有效位)。
返回布尔值列表 answer
,只有当 5
整除时,答案 answer[i]
为 true
,否则为 false
。
示例
提示
1 <= len(A) <= 3e4
;A[i] in (0, 1)
。
题解
循环
简化
947. 移除最多的同行或同列石头
题目
n
块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。
如果一块石头的同行或者同列上有其他石头存在,那么就可以移除这块石头。
给你一个长度为 n
的数组 stones
,其中 stones[i] = [xi, yi]
表示第 i
块石头的位置,返回可以移除的石子的最大数量。
示例
提示
1 <= len(stones) <= 1e3
;0 <= xi, yi <= 1e4
;- 不会有两块石头放在同一个坐标点上。
题解
并查集。同行、同列的点相连,最终最少剩余连通分支数个点(每一连通分支按任意遍历序的倒序移除点),最终结果(最多可移除的点数)为总点数减连通分支数。
1232. 缀点成线
题目
在一个 coordinates
来分别记录它们的坐标,其中 coordinates[i] = [x, y]
表示横坐标为 x
,纵坐标为 y
的点。
请你来判断,这些点是否在该坐标系中属于同一条直线上,是则返回 true
,否则请返回 false
。
示例
提示
2 <= len(coordinates) <= 1e3
;len(coordinates[i]) == 2
;-1e4 <= coordinates[i][0], coordinates[i][1] <= 1e4
;coordinates
中不含重复的点。
题解
数学题。
721. 账户合并
题目
给定一个列表 accounts
,每个元素 accounts[i]
是一个字符串列表,其中第一个元素 accounts[i][0]
是名称,其余元素是 emails
表示该账户的邮箱地址。
现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。
合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是按顺序排列的邮箱地址。账户本身可以以任意顺序返回。
示例
提示
1 <= len(accounts) <= 1e3
;1 <= len(accounts[i]) <= 10
;1 <= len(accounts[i][j]) <= 30
。
题解
并查集。
1584. 连接所有点的最小费用
题目
给你一个 points
数组,表示 points[i] = [xi, yi]
,代表点
连接点
其中
请你返回将所有点连接的最小总费用。只有任意两点之间有且仅有一条简单路径时,才认为所有点都已连接。
示例
提示
1 <= len(points) <= 1e3
;-1e6 <= xi, yi <= 1e6
;- 所有点
(xi, yi)
两两不同。
题解
Kruskal
并查集记录连通性。
Prim
628. 三个数的最大乘积
题目
给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
示例
注意
- 给定的整型数组长度范围是
,数组中所有的元素范围是 ; - 输入的数组中任意三个数的乘积不会超出 32 位有符号整数的范围。
题解
最大乘积在最大的三个元素或最小的两个元素和最大的元素取得。
排序
扫描
989. 数组形式的整数加法
题目
对于非负整数 X
而言,X
的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231
,那么其数组形式为 [1, 2, 3, 1]
。
给定非负整数 X
的数组形式 A
,返回整数 X + K
的数组形式。
示例
提示
1 <= len(A) <= 1e4
;0 <= A[i] <= 9
;0 <= K <= 1e4
;- 如果
len(A) > 1
,那么A[0] != 0
。
题解
列表
双端队列
1319. 连通网络的操作次数
题目
用以太网线缆将 n
台计算机连接成一个网络,计算机的编号从 0
到 n - 1
。线缆用 connections
表示,其中 connections[i] = [a, b]
连接了计算机 a
和 b
。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections
,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1
。
示例
提示
1 <= n <= 1e5
;1 <= len(connections) <= min(n * (n - 1) / 2, 1e5)
;len(connections[i]) == 2
;0 <= connections[i][0], connections[i][1] < n
;connections[i][0] != connections[i][1]
;- 没有重复的连接;两台计算机不会通过多条线缆连接。
题解
并查集。每次操作可合并两个连通分支,结果即连通分支数减一;若线缆数少于 n - 1
,则线缆数量不足。
674. 最长连续递增序列
题目
给定一个未经排序的整数数组,找到最长且连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l < r
确定,如果对于每个 l <= i < r - 1
,都有 nums[i] < nums[i + 1]
,那么子序列 nums[l:r]
就是连续递增子序列。
示例
提示
0 <= len(nums) <= 1e4
;-1e9 <= nums[i] <= 1e9
。
题解
959. 由斜杠划分区域
题目
在由 grid
中,每个 '/'
、'\\'
或空格构成。这些字符会将方块划分为一些共边的区域。(请注意,反斜杠字符是转义的,因此用 '\\'
表示)
返回区域的数目。
示例
提示
1 <= len(grid) == len(grid[i]) <= 30
;grid[i][j] in ('/', '\\', ' ')
。
题解
并查集。共
1128. 等价多米诺骨牌对的数量
题目
给你一个由一些多米诺骨牌组成的列表 dominoes
。
如果其中某一张多米诺骨牌可以通过旋转 0
度或 180
度得到另一张多米诺骨牌,我们就认为这两张牌是等价的。
形式上,dominoes[i] = [a, b]
和 dominoes[j] = [c, d]
等价的前提是 a == c
且 b == d
,或是 a == d
且 b == c
。
在 0 <= i < j < len(dominoes)
的前提下,找出满足 dominoes[i]
和 dominoes[j]
等价的骨牌对 (i, j)
的数量。
示例
提示
1 <= len(dominoes) <= 4e4
;1 <= dominoes[i][j] <= 9
。
题解
1579. 保证图可完全遍历
题目
Alice 和 Bob 共有一个无向图,其中包含 n
个节点和 3
种类型的边:
- 类型 1:只能由 Alice 遍历;
- 类型 2:只能由 Bob 遍历;
- 类型 3:Alice 和 Bob 都可以遍历。
给你一个数组 edges
,其中 edges[i] = [type_i, u_i, v_i]
表示节点 u_i
和 v_i
之间存在类型为 type_i
的双向边。请你在保证图仍能够被 Alice 和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。
返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1
。
示例
提示
1 <= n <= 1e5
;1 <= len(edges) <= min(1ee5, 3 * n * (n - 1) // 2)
;len(edges[i]) == 3
;1 <= edges[i][0] <= 3
;1 <= edges[i][1] < edges[i][2] <= n
;- 所有元组
(type_i, u_i, v_i)
互不相同。
题解
- 并查集,Kruscal。逆向思维,向空图添加边,优先使用公共边;
- 提前退出。
724. 寻找数组的中心索引
题目
给定一个整数类型的数组 nums
,请编写一个能够返回数组中心索引的方法。
我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。
如果数组不存在中心索引,那么我们应该返回 -1
。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。
示例
说明
0 <= len(nums) <= 1e4
;-1e3 <= nums[i] <= 1e3
。
题解
1631. 最小体力消耗路径
题目
你准备参加一场远足活动。给你一个二维 heights
,其中 heights[row][col]
表示格子 (row, col)
的高度。一开始你在最左上角的格子 (0, 0)
,且你希望去最右下角的格子 (rows - 1, cols - 1)
(注意下标从 0
开始编号)。你每次可以往上、下、左、右四个方向之一移动,你想要找到耗费体力值最小的一条路径。
一条路径耗费的体力值是路径上相邻格子之间高度差绝对值的最大值决定的。
请你返回从左上角走到右下角的最小体力消耗值。
示例
提示
rows == len(heights)
;cols == len(heights[i])
;1 <= rows, cols <= 1e2
;1 <= heights[i][j] <= 1e6
。
题解
排序并查集
堆并查集
778. 水位上升的泳池中游泳
题目
在一个 grid
中,每一个方格的值 grid[i][j]
表示在位置 (i, j)
的平台高度。
现在开始下雨了。当时间为 t
时,此时雨水导致水池中任意位置的水位为 t
。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。
你从坐标方格的左上平台 (0,0)
出发。最少耗时多久你才能到达坐标方格的右下平台 (n - 1, n - 1)
?
示例
提示
2 <= n <= 50
;grid[i][j]
是range(n * n)
的排列。
题解
并查集
可仿照上题“1631. 最小体力消耗路径”。
839. 相似字符串组
题目
如果交换字符串 X
中的两个不同位置的字母,使得它和字符串 Y
相等,那么称 X
和 Y
两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。
例如,"tars"
和 "rats"
是相似的(交换 0
与 2
的位置);"rats"
和 "arts"
也是相似的,但是 "star"
不与 "tars"
、"rats"
、"arts"
相似。
总之,它们通过相似性形成了两个关联组:{"tars", "rats", "arts"}
和 {"star"}
。注意,"tars"
和 "arts"
是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。
给你一个字符串列表 strs
。列表中的每个字符串都是 strs
中其它所有字符串的一个字母异位词。请问 strs
中有多少个相似字符串组?
示例
提示
1 <= len(strs) <= 1e2
;1 <= len(strs[i]) <= 1e3
;sum(map(len, strs)) <= 2e4
;strs[i]
只包含小写字母;strs
中的所有单词都具有相同的长度,且是彼此的字母异位词。
备注
字母异位词(anagram),一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。
题解
并查集。