leetcode update

This commit is contained in:
gameloader 2024-10-11 10:10:23 +08:00
parent 58999df498
commit 5983ce39b3

View File

@ -15104,8 +15104,11 @@ public:
} }
}; };
``` ```
## day225 2024-10-09 ## 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: A parentheses string is valid if and only if:
It is the empty string, 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) ![10090ZydPlF1SeVw](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/10090ZydPlF1SeVw.png)
### 题解 ### 题解
本题解法和昨天的题目类似左括号可以放在栈中等待匹配如果栈中为空且扫描到了右括号则必须要前面补充一个左括号与之匹配此时要将添加括号的数量加1最终将字符串全部扫描完成后栈中剩余的左括号的数量即为无法匹配的左括号数量需要添加相同数量的右括号来匹配因此将添加括号数量加上该数量得到最终结果。同样因为栈中保存的一直为左括号因此无需真的构造一个栈并将左括号入栈只需用一个变量标记当前栈中的数量即可。 本题解法和昨天的题目类似左括号可以放在栈中等待匹配如果栈中为空且扫描到了右括号则必须要前面补充一个左括号与之匹配此时要将添加括号的数量加1最终将字符串全部扫描完成后栈中剩余的左括号的数量即为无法匹配的左括号数量需要添加相同数量的右括号来匹配因此将添加括号数量加上该数量得到最终结果。同样因为栈中保存的一直为左括号因此无需真的构造一个栈并将左括号入栈只需用一个变量标记当前栈中的数量即可。
### 代码 ### 代码
```cpp
```cpp
class Solution { class Solution {
public: public:
int minAddToMakeValid(string s) { 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<int>& nums) {
int n = nums.size();
vector<pair<int, int>> 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<int>& nums) {
int n = nums.size();
stack<int> 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<int, std::vector<int>, std::greater<int>> 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<vector<int>>& times, int targetFriend) {
int max_seat = 0;
unordered_map<int, vector<int>> 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;
}
};
```