文章目录
- [力扣 2946. 循环移位后的矩阵相似检查](#力扣 2946. 循环移位后的矩阵相似检查)
- [力扣 155. 最小栈](#力扣 155. 最小栈)
- 踩坑记录

力扣 2946. 循环移位后的矩阵相似检查
题目描述
示例 1:
输入:mat = [[1,2,1,2],[5,5,5,5],[6,3,6,3]], k = 2
输出:true
解释:
初始矩阵如图一所示。
图二表示对奇数行右移一次且对偶数行左移一次后的矩阵状态。
图三是经过两次循环移位后的最终矩阵状态,与初始矩阵相同。
因此,返回 true 。
示例 2:输入:mat = [[2,2],[2,2]], k = 3
输出:true
解释:由于矩阵中的所有值都相等,即使进行循环移位,矩阵仍然保持不变。因此,返回 true 。
示例 3:输入:mat = [[1,2]], k = 1
输出:false
解释:循环移位一次后,mat = [[2,1]],与初始矩阵不相等。因此,返回 false 。
提示:1 <= mat.length <= 25
1 <= mat[i].length <= 25
1 <= mat[i][j] <= 25
1 <= k <= 50
思路简述
核心思路其实很简单:无论对一行进行左移 k 次还是右移 k 次,判断移位后矩阵能否复原的底层逻辑是完全一致的。
这就像我们玩三阶魔方时,把红色面正对自己,无论向左还是向右旋转某一层,都需要旋转 4 次才能让红色面完全回到正对自己的初始状态 ------ 循环移位的核心就是周期性。
对于矩阵中任意一个元素 mat[i][j],经过题目要求的循环移位后,它的目标位置可以直接通过公式推导得出,最终只需验证 mat[i][j] 是否与 mat[i][(j + k) % n] 相等即可。这里对 n 取模,是为了处理 k 大于行长度 n 的情况,避免重复循环移位带来的索引越界问题,同时也能直接抵消掉完整周期的无效移位。
基于这个规律,我们完全不需要实际模拟每一次移位操作,只需遍历矩阵做一次等式校验,就能得出最终结果。
代码实现
cpp
class Solution {
public:
bool areSimilar(vector<vector<int>>& mat, int k) {
int m = mat.size(), n = mat[0].size();
for(int i = 0; i < m; i++)
{
for(int j = 0; j < n; j++)
{
if(mat[i][j] != mat[i][(j + k) % n])
return false;
}
}
return true;
}
};
复杂度分析
- 时间复杂度:O(mn),需遍历矩阵中所有元素。
- 空间复杂度:O(1),仅使用常数额外空间。
力扣 155. 最小栈
题目描述
示例 1:
输入:
"MinStack","push","push","push","getMin","pop","top","getMin"
\[\],\[-2\],\[0\],\[-3\],\[\],\[\],\[\],\[\]
输出:
null,null,null,null,-3,null,0,-2
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:-231 <= val <= 231 - 1
pop、top 和 getMin 操作总是在 非空栈 上调用
push, pop, top, and getMin最多被调用 3 * 104 次
思路简述
最小栈的核心需求是在常数时间内获取最小值 。我们可以用双栈实现(用数组实现底层逻辑同理,核心思路完全一致):
- 主栈
st1:作为标准栈,完整存储所有入栈的元素,支持常规的 push、pop、top 操作; - 辅助栈
st2:专门同步记录每一次入栈后,当前栈内的最小值。
具体操作逻辑:
- push :将元素压入
st1,若当前元素小于st2的栈顶元素,则将其压入st2,否则将st2的栈顶元素再次压入st2("占位"操作,目的是简化pop逻辑)。 - pop :同时弹出
st1和st2的栈顶元素。 - getMin :
st2的栈顶元素即为当前最小值。
代码实现
cpp
class MinStack {
public:
MinStack() {
st2.push(INT_MAX);
}
void push(int x)
{
st1.push(x);
if(st2.top() > x)
st2.push(x);
else
st2.push(st2.top());
}
void pop() {
st1.pop();
st2.pop();
}
int top() {
return st1.top();
}
int getMin() {
return st2.top();
}
stack<int> st1;
stack<int> st2;
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
复杂度分析
- 时间复杂度:所有操作(push、pop、top、getMin)均为 O(1)。
- 空间复杂度:O(n),需额外使用一个栈存储最小值。
踩坑记录
-
刚拿到「循环移位后的矩阵相似检查」这道题时,看到是简单题,第一反应是想硬凹纯数学规律的O(1)解法,结果越想越复杂,特殊情况层出不穷,最后才发现完全没必要。这里也引出一个纠结的问题:做算法题时,到底该直接模拟,还是该深挖数学规律?
-
最小栈这道题里,有个很容易忽略的细节:必须在构造函数中给辅助栈
st2先压入一个INT_MAX完成初始化。如果不做这个操作,第一次调用push时访问st2.top()会直接触发空栈访问的报错,这个小细节很容易在写代码时漏掉。
这里给总结一个超好用的判断口诀,希望能够帮助大家,刷题时扫一眼就能快速做决策:
小数据,直接模拟。
大数据,必找规律。
步骤清,模拟稳。
结果能算,数学冲。
就像今天这道矩阵题,矩阵行列数最大才25,k最大也只有50,这种小数据范围,直接模拟或者用简化后的规律遍历,远比死磕O(1)数学解法划算得多,不仅写得快,还不容易出错。
今天的两道题都是校招、社招面试里的高频基础题,一道是数组矩阵的核心操作题,一道是栈结构的经典设计题,吃透了对打牢算法基础非常有帮助。
如果这篇题解对你有帮助,麻烦点个点赞 +收藏 ,也可以关注我,后续会持续更新力扣每日一题的详细题解,还有高频面试算法的保姆级讲解,陪你一起刷穿力扣!


输入:mat = [[1,2,1,2],[5,5,5,5],[6,3,6,3]], k = 2