很久之前我面试曾遇到过这道题目,现场写的非常混乱。这道题目应该算是难题,难在对边界条件的处理。
如何发现规律,发现不变式,并能保证简单性是关键。一个明显的不变式是(→ ↓ ← ↑ )如何让它顺畅的循环?
我们可以用两个变量来限制循环,一个循环中两个行是存在关系的:rowBeg+rowEnd =row 以及 *Beg <= *End,也可以用*Beg来表达*End,但会发现用四个变量来表示程序会变得更加简单。这道题最难处理的是向左和向上的情况,因为不能保证每次操作都是合法的,为什么呢?因为在前两个操作:++rowBeg和--colEnd,可能会导致*Beg>*End的情况出现。举一个例子:假设只有一行n列,此时++rowBeg,结果就是rowBeg>rowEnd,如果此时还执行第三个操作就会越界。
特殊情况呢?例如只有一个元素,只有一行或只有一列,都对吗?
比较特殊的是只有一个元素的情况:
→:会执行
↓ :不执行。for循环中的row检查失败
←:不执行。行检查成功;虽然上面的for没有执行,但是后面的--colEnd执行了,故for循环的列检查依然失败。
↑ :不执行。列检查失败。
其他情况就更符合了。所以这段代码是极其优美的,把极特殊的情况也包含在不变式中,而只添加了两个 if 检查。之所以可以这么优美,主要得益于4个变量的使用,控制力大大增强。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int> > &matrix) {
vector<int> answer;
if(matrix.size()==0) return answer;
int row(matrix.size()-1),col(matrix[0].size()-1);
int rowBeg=0,rowEnd=row,colBeg=0,colEnd=col;
while(rowBeg<=rowEnd and colBeg<=colEnd){
for(int c=colBeg; c<=colEnd; ++c) //row ->
answer.push_back(matrix[rowBeg][c]);
++rowBeg;
for(int r=rowBeg; r<=rowEnd ; ++r) //col v
answer.push_back(matrix[r][colEnd]);
--colEnd;
if(rowBeg<=rowEnd){
for(int rc=colEnd ; rc>=colBeg ; --rc) //row <-
answer.push_back(matrix[rowEnd][rc]);
}
--rowEnd;
if(colBeg<=colEnd){
for(int rr=rowEnd ; rr>=rowBeg ; --rr) //col ^
answer.push_back(matrix[rr][colBeg]);
}
++colBeg;
}
return answer;
}
};