Leetcode review
399. Evaluate Division
问题描述:
You are given an array of variable pairs equations
and an array of real numbers values
, where equations[i] = [Ai, Bi]
and values[i]
represent the equation Ai / Bi = values[i]
. Each Ai
or Bi
is a string that represents a single variable.
You are also given some queries
, where queries[j] = [Cj, Dj]
represents the jth
query where you must find the answer for Cj / Dj = ?
.
Return the answers to all queries. If a single answer cannot be determined, return -1.0
.
Note: The input is always valid. You may assume that evaluating the queries will not result in division by zero and that there is no contradiction.
Note: The variables that do not occur in the list of equations are undefined, so the answer cannot be determined for them.
Example 1:
1 | Input: equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]] |
Example 2:
1 | Input: equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]] |
Example 3:
1 | Input: equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]] |
这是一道典型的图论相关问题,思路是构造一个邻接矩阵matrix
, matrix[i][j]
代表i/j
的值,如果没有这个值就为0。
构造好这个矩阵之后就可以通过BFS去递归的寻找关系,比如在Example 1中需要找到a/c
,那么就可以先通过dfs找到a/b
,然后再通过dfs进一步找到b/c
从而获得a/c
。
具体的代码思路如下
1 | class Solution { |
时间复杂度分析:
构建map映射,即字符串和matrix中对应下标时的复杂度为
O(E)
,E为Equations的大小。构建邻接矩阵时的复杂度为
O(E)
。dfs方法在调用时最坏情况下会遍历邻接矩阵的每一个值,假设共有n个不同的字符串,即邻接矩阵有n^2个值,所以时间复杂度为
O(n^2)
。for循环遍历queries时,假设共有Q个query,那么每次调用一次dfs,时间复杂度为
O(Q * n^2)
综上时间复杂度为O(E + Q * n^2)
。
空间复杂度分析:
- matrix共有n^2个节点,复杂度为
O(n^2)
- map共存储n个节点,复杂度为
O(n)
- dfs时递归的深度可能会达到所有节点,复杂度为
O(n)
- dfs时的set最坏情况会包含所有节点,复杂度为
O(n)
- res数组假设有Q个query,复杂度为
O(Q)
综上空间复杂度为O(Q + n^2)
994. Rotting Oranges
问题描述:
![](https://pics.findfuns.org/Problem 994.png)
思路是先遍历grid,如果找到“烂橘子”就加入到Queue中,遍历完成之后对Queue中的所有“烂橘子”进行BFS并记录每次BFS的时间,动态更新最长时间。最后检查一遍grid,如果还存在新鲜的橘子就返回-1,如果没有就返回最长时间。
代码如下:
1 | class Solution { |
时间复杂度分析:
- 两个for循环的时间复杂度为
O(n*m)
,n和m分别为grid的长和宽 - bfs最坏情况下会遍历每一个节点,时间复杂度为O(n*m)。
综上时间复杂度为O(n*m)
空间复杂度分析:
- queue最坏情况下会包含所有节点,空间复杂度为
O(n*m)
综上空间复杂度为O(n*m)
875. Koko Eating Bananas
Koko loves to eat bananas. There are n
piles of bananas, the ith
pile has piles[i]
bananas. The guards have gone and will come back in h
hours.
Koko can decide her bananas-per-hour eating speed of k
. Each hour, she chooses some pile of bananas and eats k
bananas from that pile. If the pile has less than k
bananas, she eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k
such that she can eat all the bananas within h
hours.
Example 1:
1 | Input: piles = [3,6,7,11], h = 8 |
Example 2:
1 | Input: piles = [30,11,23,4,20], h = 5 |
Example 3:
1 | Input: piles = [30,11,23,4,20], h = 6 |
可以使用二分查找不断缩小符合要求的最小速度,直到找到最小的速度
代码如下:
1 | class Solution { |
因为每一堆香蕉的最大数量为10^9,所以可以设置最大速度为10^9,最小速度为1。然后就可以进行二分查找,不断缩小速度。
值得注意的是在check()方法
中用于记录用时的变量hours
需要设置为long,不然会有溢出的风险。
时间复杂度分析:
- piles的长度为n,每次二分查找都需要遍历一次piles数组,复杂度为
O(n)
- 二分查找的范围是1-10^9,所以复杂度为
O(10^9)
- 综上时间复杂度为
O(10^9n)
空间复杂度为O(1)
962. Maximum Width Ramp
A ramp in an integer array nums
is a pair (i, j)
for which i < j
and nums[i] <= nums[j]
. The width of such a ramp is j - i
.
Given an integer array nums
, return the maximum width of a ramp in nums
. If there is no ramp in nums
, return 0
.
Example 1:
1 | Input: nums = [6,0,8,2,1,5] |
Example 2:
1 | Input: nums = [9,8,1,0,1,9,4,0,4,1] |
这道题其实简单来说就是找到和每个元素对应的不小于它的最远的元素,并且得到距离的最大值。
具体的做法是维护一个单调递减栈,从左向右遍历。再从右向左遍历,如果栈顶的元素小于等于遍历到的元素,就出栈并记录最大距离,知道栈空。
代码如下:
1 | class Solution { |
时间复杂度分析:
- 维护单调栈需要遍历每个元素,
O(n)
。 - 第二次从右向左遍历元素最坏情况下需要遍历全部元素,
O(n)
。
时间复杂度为O(n)
。
空间复杂度分析:
- 最坏情况
stack
需要记录全部元素,O(n)
。
空间复杂度为O(n)
。
2406. Divide Intervals Into Minimum Number of Groups
You are given a 2D integer array intervals
where intervals[i] = [lefti, righti]
represents the inclusive interval [lefti, righti]
.
You have to divide the intervals into one or more groups such that each interval is in exactly one group, and no two intervals that are in the same group intersect each other.
Return the minimum number of groups you need to make.
Two intervals intersect if there is at least one common number between them. For example, the intervals [1, 5]
and [5, 8]
intersect.
Example 1:
1 | Input: intervals = [[5,10],[6,8],[1,5],[2,3],[1,10]] |
Example 2:
1 | Input: intervals = [[1,3],[5,6],[8,10],[11,13]] |
这道题可以用时间线和事件的思路去解决,不必拘泥于时间对,而是把每一个时间对拆开,将其视为开始时间和结束时间。
同时使用一个最小堆对时间进行排序,当存在开始时间和结束时间相同时先处理开始时间。维护一个变量记录同时存在的事件的最大数量,即为答案。
代码如下:
1 | class Solution { |
时间复杂度分析:
- 假设intervals有n个事件,那么一共有2n个时间点,插入堆的复杂度为
O(log2n)
,综合复杂度为O(2nlog(2n)) = O(nlogn)
。
空间复杂度分析:
- 堆需要
O(2n) = O(n)
的空间
632. Smallest Range Covering Elements from K Lists
You have k
lists of sorted integers in non-decreasing order. Find the smallest range that includes at least one number from each of the k
lists.
We define the range [a, b]
is smaller than range [c, d]
if b - a < d - c
or a < c
if b - a == d - c
.
Example 1:
1 | Input: nums = [[4,10,15,24,26],[0,9,12,20],[5,18,22,30]] |
Example 2:
1 | Input: nums = [[1,2,3],[1,2,3],[1,2,3]] |
涉及到“最大”“最小”问题时,往往需要考虑使用heap,因为这类问题需要频繁地获得最大最小值,而堆可以实现在O(1)
的复杂度下得到最值,从而降低时间复杂度。
每一轮将一列元素存入heap,将最小值移出,并且动态的更新最大最小值,并记录range,再将移出元素的下一个元素加入heap,直到heap中的元素数量小于nums中数组的数量,最终获得的最小range即为答案。
1 | class Solution { |
1 | 例一的每一轮处理过程如下 |
时间复杂度分析:
- 设nums中共有k个数组,设共有N个元素,最坏情况下heap需要遍历每一个元素,每次插入和删除元素的复杂度为
O(logk)
,时间复杂度为O(Nlogk)
。
空间复杂度分析:
- heap中始终存在k个元素,空间复杂度为
O(k)
1942. The Number of the Smallest Unoccupied Chair
There is a party where n
friends numbered from 0
to n - 1
are attending. There is an infinite number of chairs in this party that are numbered from 0
to infinity
. When a friend arrives at the party, they sit on the unoccupied chair with the smallest number.
- For example, if chairs
0
,1
, and5
are occupied when a friend comes, they will sit on chair number2
.
When a friend leaves the party, their chair becomes unoccupied at the moment they leave. If another friend arrives at that same moment, they can sit in that chair.
You are given a 0-indexed 2D integer array times
where times[i] = [arrivali, leavingi]
, indicating the arrival and leaving times of the ith
friend respectively, and an integer targetFriend
. All arrival times are distinct.
Return the chair number that the friend numbered targetFriend
will sit on.
Example 1:
1 | Input: times = [[1,4],[2,3],[4,6]], targetFriend = 1 |
Example 2:
1 | Input: times = [[3,10],[1,5],[2,6]], targetFriend = 0 |
- 这个问题可以考虑将每个人的时间拆开,分成开始时间和结束时间。将拆开后的时间以数组的形式存入小顶堆中,arr[0]是时间,arr[1]用来记录是第几个人,arr[2]用来记录是到达时间还是离开时间。以arr[0]为依据排序。
- 同时,一个优先队列来记录当前时刻下空的椅子,这样总是可以得到最小的可以利用的椅子。
- 用一个Map来记录当前时刻下已经被占用的椅子,key为人的徐浩,value是椅子序号。
- 具体的流程是,按发生顺序依次遍历每一个时间。如果为到达时间,就从availableChairs中分配一把椅子,并存入occupiedChairs。并且检查是否是targetFriend;如果为结束时间,就将对应的occupiedChairs中的椅子放回avaliableChairs。
1 | class Solution { |
时间复杂度分析:
- 设一共有n个人,events共插入2n次,每次插入的时间复杂度为
O(logn)
,复杂度为O(2nlog2n) = O(nlogn)
。 - 将所有椅子加入avaliableChairs,时间复杂度为
O(nlogn)
。 - 依次遍历每个event,最坏情况下每次都要取一个新的椅子,从avaliableChairs取椅子复杂度为
O(logn)
, 插入occupiedChairs复杂度为(O(1)),总复杂度为2n(O(logn) + O(1)) = O(nlogn)
。
综上时间复杂度为O(nlogn)
。
空间复杂度分析:
- events需要
O(2n)
- avaliableChair最多需要
O(n)
- occupiedChair最多需要
O(n)
综上空间复杂度为O(n)
。