From 5983ce39b375747c7c6179476779a24094625b26 Mon Sep 17 00:00:00 2001 From: gameloader Date: Fri, 11 Oct 2024 10:10:23 +0800 Subject: [PATCH] leetcode update --- content/posts/leetcode.md | 190 +++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 2 deletions(-) diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index 60c20ac..b1bd51b 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -15104,8 +15104,11 @@ public: } }; ``` + ## day225 2024-10-09 -### 921. Minimum Add to Make Parentheses Valid + +### 921. Minimum Add to Make Parentheses Valid + A parentheses string is valid if and only if: It is the empty string, @@ -15119,10 +15122,12 @@ Return the minimum number of moves required to make s valid. ![10090ZydPlF1SeVw](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/10090ZydPlF1SeVw.png) ### 题解 + 本题解法和昨天的题目类似,左括号可以放在栈中等待匹配,如果栈中为空且扫描到了右括号则必须要前面补充一个左括号与之匹配,此时要将添加括号的数量加1,最终将字符串全部扫描完成后,栈中剩余的左括号的数量即为无法匹配的左括号数量,需要添加相同数量的右括号来匹配,因此将添加括号数量加上该数量得到最终结果。同样,因为栈中保存的一直为左括号,因此无需真的构造一个栈并将左括号入栈,只需用一个变量标记当前栈中的数量即可。 ### 代码 -```cpp + +```cpp class Solution { public: int minAddToMakeValid(string s) { @@ -15144,3 +15149,184 @@ public: } }; ``` + +## day226 2024-10-10 + +### 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. + +![1010CxODxExtAzxK](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1010CxODxExtAzxK.png) + +### 题解 + +本题先排序,排序的作用在于将乱序的数字整理为有序,有序的作用在于将数字之间的相对大小信息和位置关联起来,适用于当某个问题对于较大数求解得到结果后就无需对更小的数字求解时,像本题中要求nums[i]<=nums[j]则可以先找到比某个数字大的所有数字,再去比较数字下标之间的关系。在排序后,对于有序数组中下标k的之后的数字都大于k,只需比较k之后的数字在原始数组中的下标和k数字的原始下标之间的大小无需再考虑之前的数字。 +如果每个数字都和其后面的数字比较下标需要n^2的时间复杂度,显然没必要每个数字都和后面的全部数字比较,只需记录下已经遍历过的数字中原始下标最小的那个,继续向后遍历时将每个数字的原始下标和这个最小值做差即得这个数字作为右端边界的最大宽度。如果遇到了下标更小的则更新最小值,同样在遍历时如果得到了更大的最大宽度则更新最大宽度。 + +### 代码 + +```cpp + +class Solution { +public: + int maxWidthRamp(vector& nums) { + int n = nums.size(); + vector> sorted(n); + + for (int i = 0; i < n; i++) { + sorted[i] = {nums[i], i}; + } + + // 按值排序 + sort(sorted.begin(), sorted.end()); + + int maxWidth = 0; + int minIndex = n; // 初始化为一个不可能的大索引 + + // 遍历排序后的数组 + for (const auto& [value, index] : sorted) { + // 更新最大宽度 + maxWidth = max(maxWidth, index - minIndex); + // 更新最小索引 + minIndex = min(minIndex, index); + } + + return maxWidth; + } +}; +``` + +### 总结 + +本题还可以使用单调栈,使用单调栈避免了排序,排序自身需要nlogn的时间复杂度,使用单调栈可以达到n的时间复杂度。单调栈需要正向遍历一遍数组,再反向遍历一遍数组。正向遍历数组时构造一个单调减的单调栈,仅保存单调减的数字和其对应的下标。在反向遍历时如果数字大于栈顶数字则弹出栈顶直到数字小于栈顶数字,弹出过程中不断计算栈顶下标和当前下标的差作为宽度。继续反向遍历重复上述过程。这样可以得到最大宽度的原因是对于反向遍历的下标k和k-1的两个数字。如果下标k的数字比栈顶数字x大。若k-1的数字也比x大,则k-1和x对应的下标s之间的距离k-1-s一定小于k-s。即如果反向遍历时两个数字对应的左侧的栈顶相同,不可能存在比最右端的数字到栈顶数字距离更大的距离存在。而单调栈从底到顶的下标是单调增的,因此如果弹出了栈顶,栈顶的下标位置只会向左移动,这样对于相同的右端,弹出栈顶只会使宽度增大。相当于第一次正向遍历保证了左端的单调性,第二次反向遍历则自带右端的单调性。这样遍历两遍数组即可得最终结果。 + +```cpp +class Solution { +public: + int maxWidthRamp(vector& nums) { + int n = nums.size(); + stack indicesStack; + + // Fill the stack with indices in increasing order of their values + for (int i = 0; i < n; i++) { + if (indicesStack.empty() || nums[indicesStack.top()] > nums[i]) { + indicesStack.push(i); + } + } + + int maxWidth = 0; + + // Traverse the array from the end to the start + for (int j = n - 1; j >= 0; j--) { + while (!indicesStack.empty() && + nums[indicesStack.top()] <= nums[j]) { + maxWidth = max(maxWidth, j - indicesStack.top()); + // Pop the index since it's already processed + indicesStack.pop(); + } + } + + return maxWidth; + } +}; +``` +## day227 2024-10-11 +### 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, and 5 are occupied when a friend comes, they will sit on chair number 2. +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. + +![1011YenBDfVA7f4P](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1011YenBDfVA7f4P.png) + +### 题解 +本题先根据arrival时间对times数组中的子数组进行排序,遍历有序的times数组,将当前空余的最小座位号的座位分配给当前朋友,同时向map中对应key为当前朋友离开时间的value数组插入分配给当前朋友的座位号。在遍历每一个新的arrival时间时,先从map中找到所有小于等于该时间的leaving对应的座位号数组。这些座位在该时间之前都处于空闲状态,因此将这些座位号加入到一个最小堆中。这样给新的朋友分配座位时只需从最小堆弹出顶部数字即为当前空余的最小座位号。这就解决了如何获得空余座位中最小座位号的问题。如果最小堆中没有任何座位号,那就将一个新的座位号分配给该朋友,同时更新当前的最大座位号。 + +### 代码 +```cpp +class MinHeap { +private: + std::priority_queue, std::greater> pq; + +public: + void insert(int value) { + pq.push(value); + } + + int extractMin() { + int minValue = pq.top(); + pq.pop(); + return minValue; + } + + int peekMin() const { + return pq.top(); + } + + bool isEmpty() const { + return pq.empty(); + } + + int size() const { + return pq.size(); + } +}; + +class Solution { +public: + int smallestChair(vector>& times, int targetFriend) { + int max_seat = 0; + unordered_map> leave_map; + MinHeap available_seats; + + // 为每个朋友添加索引,并按到达时间排序 + for (int i = 0; i < times.size(); i++) { + times[i].push_back(i); + } + sort(times.begin(), times.end()); + + int last_arrival = 0; + for (const auto& time : times) { + int arrival = time[0]; + int leaving = time[1]; + int friend_index = time[2]; + + // 处理在上一个到达时间到当前到达时间之间离开的朋友 + for (int t = last_arrival + 1; t <= arrival; ++t) { + if (leave_map.find(t) != leave_map.end()) { + for (int seat : leave_map[t]) { + available_seats.insert(seat); + } + leave_map.erase(t); + } + } + + int assigned_seat; + if (!available_seats.isEmpty()) { + assigned_seat = available_seats.extractMin(); + } else { + assigned_seat = max_seat++; + } + + // 如果是目标朋友,返回分配的座位 + if (friend_index == targetFriend) { + return assigned_seat; + } + + // 更新离开时间映射 + leave_map[leaving].push_back(assigned_seat); + + last_arrival = arrival; + } + + return -1; + } +}; + +```