题解 | 螺旋矩阵 这个边界收缩的方法很妙
螺旋矩阵
https://www.nowcoder.com/practice/7edf70f2d29c4b599693dc3aaeea1d31
只要有一条边不满足条件(即边界发生交叉),就意味着矩阵中所有剩余的元素都已经被遍历完了,或者根本不存在剩余元素了。 继续执行只会导致重复遍历或数组越界。
这是一个非常深刻且关键的问题!这触及了螺旋矩阵算法的核心逻辑。
简单来说,只要有一条边不满足条件(即边界发生交叉),就意味着矩阵中所有剩余的元素都已经被遍历完了,或者根本不存在剩余元素了。 继续执行只会导致重复遍历或数组越界。
我们可以通过分析边界收缩的过程来理解这一点。
核心思想:边界交叉 = 遍历结束
螺旋遍历的本质是逐层剥离矩阵。每完成一个方向的遍历,我们就会将对应的边界向内收缩一步。
up > down:意味着上边界已经跑到了下边界的下面。说明所有行都处理完了。
left > right:意味着左边界已经跑到了右边界的右边。说明所有列都处理完了。
只要发生以上任何一种情况,就说明“地盘”已经被瓜分完毕,没有新的、未访问的元素了。
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param matrix int整型vector<vector<>>
* @return int整型vector
*/
vector<int> spiralOrder(vector<vector<int> >& matrix) {
// write code here
vector<int> res;
int row=matrix.size();
if(row==0)return res;
int col=matrix[0].size();
/*
卡尔讲的循环不变量很精彩 但官解更胜一筹。
都是按照顺时针方向(右 -> 下 -> 左 -> 上)一圈一圈地“剥洋葱,只要保持这个顺序对了 且一次只访问边界 并且没有重复访问 并且有终止条件 那他就是正确的
这个叫做边界收缩法。
*/
// vector<int> res(row*col);
//这里不应该初始化啊,不然结果数组的前 row*col 个元素全是 0,后面才接上你遍历出来的真实数据
if(row==0||col==0)return res;
int up=0,left=0,right=col-1,down=row-1;
while((up<=down)&&(right>=left)){
if(right>=left){
for(int i=left;i<=right;i++){
res.push_back(matrix[up][i]);
}
}
else break;
up++;
if(up<=down){
for(int i=up;i<=down;i++){
res.push_back(matrix[i][right]);
}
}
else break;
right--;
if(right>=left){
for(int i=right;i>=left;i--){
res.push_back(matrix[down][i]);
}
}
else break;
down--;
if(up<=down){
for(int i=down;i>=up;i--){
res.push_back(matrix[i][left]);
}
}
else break;
left++;
}
return res;
}
};