leetcode update

This commit is contained in:
gameloader 2024-11-27 23:27:29 +08:00
parent 7687287272
commit 386591c939

View File

@ -18136,8 +18136,11 @@ public:
} }
}; };
``` ```
## day259 2024-11-22 ## day259 2024-11-22
### 1072. Flip Columns For Maximum Number of Equal Rows
### 1072. Flip Columns For Maximum Number of Equal Rows
You are given an m x n binary matrix matrix. You are given an m x n binary matrix matrix.
You can choose any number of columns in the matrix and flip every cell in that column (i.e., Change the value of the cell from 0 to 1 or vice versa). You can choose any number of columns in the matrix and flip every cell in that column (i.e., Change the value of the cell from 0 to 1 or vice versa).
@ -18147,6 +18150,7 @@ Return the maximum number of rows that have all values equal after some number o
![1122r0stlh0LaeX9](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1122r0stlh0LaeX9.png) ![1122r0stlh0LaeX9](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1122r0stlh0LaeX9.png)
### 题解 ### 题解
本题先思考简单例子对于两行01串在什么情况下通过多次翻转同一个位置上的数字最终可以使得两行行内数字完全相同如0010显然无论怎么翻转都只可能有一行数字是完全相同的另一行则不可能相同再考虑1001只需翻转任意一列两行数字都会相同。由此可以猜测对于任意两行数字若这两行数字每一位上的数都不相同则这两行数字最终可以通过翻转实现两行数字行内完全相同注意数字只能取01两种因此若两行数字满足每一位都不相同要想三行数字满足行内相同第三行数字必定和这两行数字中的某一行完全相同。 本题先思考简单例子对于两行01串在什么情况下通过多次翻转同一个位置上的数字最终可以使得两行行内数字完全相同如0010显然无论怎么翻转都只可能有一行数字是完全相同的另一行则不可能相同再考虑1001只需翻转任意一列两行数字都会相同。由此可以猜测对于任意两行数字若这两行数字每一位上的数都不相同则这两行数字最终可以通过翻转实现两行数字行内完全相同注意数字只能取01两种因此若两行数字满足每一位都不相同要想三行数字满足行内相同第三行数字必定和这两行数字中的某一行完全相同。
则若能通过翻转使得任意两行的行内数字完全相同,这两行要么相同,要么相反。我们只需统计相同行和对应的相反行的数量和,找到最大值就得到本题的解。 则若能通过翻转使得任意两行的行内数字完全相同,这两行要么相同,要么相反。我们只需统计相同行和对应的相反行的数量和,找到最大值就得到本题的解。
@ -18154,25 +18158,26 @@ Return the maximum number of rows that have all values equal after some number o
问题在于如何统计考虑要统计的行要么完全相同要么相反则可以将二者用一个同样的值来表示此处就要用到哈希问题是如果将每一行中的每一位视为简单的二进制位考虑行的长度最大为300显然不能用整数直接装下因此要么使用分块哈希要么充分利用c++中已有的哈希实现,将每一行转换为字符串再作为哈希的键。由于相反的行我们想使用同一个键值来表示,因此对每一行都构造出该行对应的字符串和该行对应的相反行的字符串,取两个字符串中字典序小的字符串,这样就将相反行都用二者中字典序小的字符串来表示,进而统计满足相同或者相反行的总数。 问题在于如何统计考虑要统计的行要么完全相同要么相反则可以将二者用一个同样的值来表示此处就要用到哈希问题是如果将每一行中的每一位视为简单的二进制位考虑行的长度最大为300显然不能用整数直接装下因此要么使用分块哈希要么充分利用c++中已有的哈希实现,将每一行转换为字符串再作为哈希的键。由于相反的行我们想使用同一个键值来表示,因此对每一行都构造出该行对应的字符串和该行对应的相反行的字符串,取两个字符串中字典序小的字符串,这样就将相反行都用二者中字典序小的字符串来表示,进而统计满足相同或者相反行的总数。
### 代码 ### 代码
```cpp
```cpp
class Solution { class Solution {
public: public:
int maxEqualRowsAfterFlips(vector<vector<int>>& matrix) { int maxEqualRowsAfterFlips(vector<vector<int>>& matrix) {
unordered_map<string, int> count; unordered_map<string, int> count;
int m = matrix.size(), n = matrix[0].size(); int m = matrix.size(), n = matrix[0].size();
for (const auto& row : matrix) { for (const auto& row : matrix) {
string pattern(n, '0'); string pattern(n, '0');
string flipped(n, '0'); string flipped(n, '0');
for (int j = 0; j < n; j++) { for (int j = 0; j < n; j++) {
pattern[j] = row[j] + '0'; pattern[j] = row[j] + '0';
flipped[j] = (1 - row[j]) + '0'; flipped[j] = (1 - row[j]) + '0';
} }
count[min(pattern, flipped)]++; count[min(pattern, flipped)]++;
} }
int maxCount = 0; int maxCount = 0;
for (const auto& [_, cnt] : count) { for (const auto& [_, cnt] : count) {
maxCount = max(maxCount, cnt); maxCount = max(maxCount, cnt);
@ -18185,11 +18190,12 @@ public:
## day260 2024-11-23 ## day260 2024-11-23
### 1861. Rotating the Box ### 1861. Rotating the Box
You are given an m x n matrix of characters box representing a side-view of a box. Each cell of the box is one of the following: You are given an m x n matrix of characters box representing a side-view of a box. Each cell of the box is one of the following:
A stone '#' A stone '#'
A stationary obstacle '*' A stationary obstacle '\*'
Empty '.' Empty '.'
The box is rotated 90 degrees clockwise, causing some of the stones to fall due to gravity. Each stone falls down until it lands on an obstacle, another stone, or the bottom of the box. Gravity does not affect the obstacles' positions, and the inertia from the box's rotation does not affect the stones' horizontal positions. The box is rotated 90 degrees clockwise, causing some of the stones to fall due to gravity. Each stone falls down until it lands on an obstacle, another stone, or the bottom of the box. Gravity does not affect the obstacles' positions, and the inertia from the box's rotation does not affect the stones' horizontal positions.
@ -18200,10 +18206,12 @@ Return an n x m matrix representing the box after the rotation described above.
![1123pEbOZz2P5uHK](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1123pEbOZz2P5uHK.png) ![1123pEbOZz2P5uHK](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1123pEbOZz2P5uHK.png)
### 题解 ### 题解
本题图里的石头挺有意思的像哪里来的魔法石。题目直观的想象是将一个容器翻转90°翻转后石头会自由落体直到落到一块比较坚实的“地面”上。考虑原来的行和翻转后的列的关系原来的第一行翻转后会变为第一列如果共有m行n列那么原来位于(p,q)位置的会变为位于(q,m-p-1)。先构建一个n x m的空数组遍历原始的m x n数组当按行遍历时统计该行中遇到过的石头的个数直到遇到一个障碍物此时将该障碍物按照转换后的位置填入空数组中并根据该障碍物前面的石头个数在空数组中该障碍物的位置向上填充对应数量的石头。如此反复即得最终转换后的数组。 本题图里的石头挺有意思的像哪里来的魔法石。题目直观的想象是将一个容器翻转90°翻转后石头会自由落体直到落到一块比较坚实的“地面”上。考虑原来的行和翻转后的列的关系原来的第一行翻转后会变为第一列如果共有m行n列那么原来位于(p,q)位置的会变为位于(q,m-p-1)。先构建一个n x m的空数组遍历原始的m x n数组当按行遍历时统计该行中遇到过的石头的个数直到遇到一个障碍物此时将该障碍物按照转换后的位置填入空数组中并根据该障碍物前面的石头个数在空数组中该障碍物的位置向上填充对应数量的石头。如此反复即得最终转换后的数组。
### 代码 ### 代码
```cpp
```cpp
class Solution { class Solution {
public: public:
vector<vector<char>> rotateTheBox(vector<vector<char>>& box) { vector<vector<char>> rotateTheBox(vector<vector<char>>& box) {
@ -18232,3 +18240,255 @@ public:
} }
}; };
``` ```
## day261 2024-11-24
### 1975. Maximum Matrix Sum
You are given an n x n integer matrix. You can do the following operation any number of times:
Choose any two adjacent elements of matrix and multiply each of them by -1.
Two elements are considered adjacent if and only if they share a border.
Your goal is to maximize the summation of the matrix's elements. Return the maximum sum of the matrix's elements using the operation mentioned above.
![1124n2svbPikMZWV](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1124n2svbPikMZWV.png)
### 题解
本题通过不断将相邻数字变为自己的相反数的操作,最终一定可以将负数变为相邻位置(相当于对负号进行了传递),这时再进行一次操作即可使得两个负数都变为正数。因此遍历并记录数组中负数的个数,同时记录下绝对值最小的数(在加和时减少的最少)。若负数个数为偶数则直接将数字全部变为正数加和,若为奇数则除绝对值最小的保持为负数外其余均按照正数加和。
因此本题可以直接将所有负数均变为正数并加和,最后根据总体负数的奇偶性再对绝对值最小的数进行加减。这样仅需遍历一遍数组就能得到结果。
这样计算没有考虑包含0的情况在包含0的情况下所有负数均可通过将负号最终传递给0从而变成正数0自身是没有符号的就像黑洞一样吸掉了全部符号。因此在包含0的情况下无需考虑负数个数的奇偶性直接将所有数字按绝对值加和就得到了最终结果。
### 代码
```cpp
class Solution {
public:
long long maxMatrixSum(vector<vector<int>>& matrix) {
int addsmall = 100001;
int nums = 0;
long long int sum = 0;
bool zero = false;
for (const auto& row : matrix){
for(const auto& num : row){
if(num > 0){
if(num < addsmall){
addsmall = num;
}
sum += num;
}else if(num < 0){
nums++;
if (-num < addsmall){
addsmall = -num;
}
sum += -num;
}else{
zero = true;
}
}
}
if(nums % 2 == 1 && !zero){
sum += -2 * addsmall;
}
return sum;
}
};
```
## day262 2024-11-25
### 773. Sliding Puzzle
On an 2 x 3 board, there are five tiles labeled from 1 to 5, and an empty square represented by 0. A move consists of choosing 0 and a 4-directionally adjacent number and swapping it.
The state of the board is solved if and only if the board is [[1,2,3],[4,5,0]].
Given the puzzle board board, return the least number of moves required so that the state of the board is solved. If it is impossible for the state of the board to be solved, return -1.
![1125NLB8Q0i1LvJO](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1125NLB8Q0i1LvJO.png)
### 题解
本题是一道难题,可以将其视为一个搜索问题,但这种搜索问题正因非常经典从而非常难。类似这种问题比较出名的场景是围棋,但围棋的棋子是属于不同方的,因此在构建棋盘状态时除了棋子自身的位置还要加上棋子的归属这一属性,而本题相对简化,不存在这个问题,相当于每个棋子仅有数字作为自身的属性。最终搜索的目标也是固定的状态。
则可以一边构造出状态树一边搜索状态树中每个节点是棋盘当前的布局边表示边相连的节点可以通过一次0的移动互相转换。通过广度优先搜索不断遍历树的每一层直到找到目标节点此时遍历的深度即为需要的移动步数而若全部遍历完后仍未达到目标状态则返回-1。
难点在于在展开这棵状态树时我们不想让底层的节点重复已经构造过的状态节点如何记录已经构造过的状态节点呢可以将棋盘上的数字按顺序写成一个字符串将字符串放入set中这样只需查看set中是否已经包含这个字符串即可知道是否已经构造过这个状态。
另一方面,对于每个位置可以替换的数字的位置是固定的,因此将每个位置可以替换的数字的位置在字符串中的下标保存起来,使用时直接将字符串的当前位置与可替换的位置进行交换即得到构造的两个新字符串。
本题如果能想到将状态作为节点,将边作为状态之间关联的连接,后续其实相当比较容易,将这个模型提炼出来本身就是一个难点。这要求我们要更深入的理解数据结构,如图,图中的节点未必只能表示一个值,它可以是一种抽象的状态,只要状态之间有某种关联就可以构造边来连接,树同理。
### 代码
```cpp
class Solution {
public:
int slidingPuzzle(vector<vector<int>>& board) {
string target = "123450";
string start;
for (const auto& row : board) {
for (int num : row) {
start += to_string(num);
}
}
vector<vector<int>> neighbors = {
{1, 3},
{0, 2, 4},
{1, 5},
{0, 4},
{3, 1, 5},
{2, 4}
};
queue<pair<string, int>> q;
unordered_set<string> visited;
q.push({start, 0});
visited.insert(start);
while (!q.empty()) {
auto [state, moves] = q.front();
q.pop();
if (state == target) {
return moves;
}
int zero_pos = state.find('0');
for (int neighbor : neighbors[zero_pos]) {
string new_state = state;
swap(new_state[zero_pos], new_state[neighbor]);
if (visited.find(new_state) == visited.end()) {
q.push({new_state, moves + 1});
visited.insert(new_state);
}
}
}
return -1;
}
};
```
## day263 2024-11-26
### 2924. Find Champion II
There are n teams numbered from 0 to n - 1 in a tournament; each team is also a node in a DAG.
You are given the integer n and a 0-indexed 2D integer array edges of length m representing the DAG, where edges[i] = [ui, vi] indicates that there is a directed edge from team ui to team vi in the graph.
A directed edge from a to b in the graph means that team a is stronger than team b and team b is weaker than team a.
Team a will be the champion of the tournament if there is no team b that is stronger than team a.
Return the team that will be the champion of the tournament if there is a unique champion, otherwise, return -1.
Notes
A cycle is a series of nodes a1, a2, ..., an, an+1 such that node a1 is the same node as node an+1, the nodes a1, a2, ..., an are distinct, and there is a directed edge from the node ai to node ai+1 for every i in the range [1, n].
A DAG is a directed graph that does not have any cycle.
![1126WmfZcBlSPLaH](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1126WmfZcBlSPLaH.png)
### 题解
本题使用简化版拓扑排序可以解决,拓扑排序在以前的题目中曾经讲解过,在有向无环图中,拓扑排序表示的是一种抽象的先后关系,如若节点均表示数字,则这种先后关系就可以是数字之间的相对大小,若把节点看成一个个在排队的人,则这种先后关系可以是一个人排在另一个人的前面。这种抽象的关系可以对应到各种实际情况中。对于本题,一条有向边相当于一支队伍打赢了另外一支队伍,那么拓扑排序的起始队伍就相当于打赢了其他队伍但没人打赢它,如果这样的队伍只有一个,显然就是冠军,不止有一个那说明还需要更多比赛。
之所以说是简化的拓扑排序在于本题理解题面可以用拓扑排序的思想但实际解题只需要记录下所有节点队伍的入度即有几支队伍打赢了它最终找到所有入度为0的队伍只有一个直接返回否则返回-1。
### 代码
```cpp
class Solution {
public:
int findChampion(int n, vector<vector<int>>& edges) {
vector<int> nodein(n,0);
for(const auto& edge : edges){
nodein[edge[1]]++;
}
int zero = -1;
for(int i=0;i<n;i++){
if(nodein[i] == 0 && zero == -1){
zero = i;
}else if(nodein[i] == 0){
return -1;
}
}
return zero;
}
};
```
## day264 2024-11-27
### 3243. Shortest Distance After Road Addition Queries I
You are given an integer n and a 2D integer array queries.
There are n cities numbered from 0 to n - 1. Initially, there is a unidirectional road from city i to city i + 1 for all 0 <= i < n - 1.
queries[i] = [ui, vi] represents the addition of a new unidirectional road from city ui to city vi. After each query, you need to find the length of the shortest path from city 0 to city n - 1.
Return an array answer where for each i in the range [0, queries.length - 1], answer[i] is the length of the shortest path from city 0 to city n - 1 after processing the first i + 1 queries.
![1127SRxWXxnZ7b3M](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/1127SRxWXxnZ7b3M.png)
### 题解
本题每次在增加了一条新路线后可以使用dijistra算法从0节点开始寻找到其他节点的最短路径一旦找到到n-1节点的最短路径就停止dijistra算法。
最初会想到在添加新路径后可以直接从最初的距离减去添加的新路径中间节省的距离但这种做法的问题在于新添加的路径可能会与之前添加过的路径有交叉则无法确定应该减去的节省的距离是多少如a->b为4,b->c为3但a->d为5,d->c为1实际选择d这条路径总距离更短。而用dijistra算法求出的到每个节点的距离已经是最短距离一旦确定了到n-1的距离就得到了最终结果。
### 代码
```cpp
class Solution {
public:
vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>>& queries) {
vector<vector<pair<int, int>>> adj(n);
for(int i = 0; i < n-1; i++) {
adj[i].push_back({i+1, 1});
}
vector<int> answer;
for(const auto& query : queries) {
int u = query[0];
int v = query[1];
adj[u].push_back({v, 1});
answer.push_back(dijkstra(adj, n, 0, n-1));
}
return answer;
}
private:
int dijkstra(const vector<vector<pair<int, int>>>& adj, int n, int start, int end) {
vector<int> dist(n, INT_MAX);
dist[start] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
pq.push({0, start});
while(!pq.empty()) {
int d = pq.top().first;
int u = pq.top().second;
pq.pop();
if(u == end) return d;
if(d > dist[u]) continue;
for(const auto& [v, weight] : adj[u]) {
if(dist[v] > dist[u] + weight) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
return dist[end];
}
};
```