最近在开心刷LintCode,其实我觉得刷题的目的就是锻炼你的解决问题的能力,不同的思想会带来不同的解决方案,找到最好的那个就是程序员的工作。但在找到最好的之前,你至少需要一点思想。
题目梗概
给定一个包含 m x n 个要素的矩阵,(m 行, n 列),按照螺旋顺序,返回该矩阵中的所有要素
如
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
应返回:
[1,2,3,6,9,8,7,4,5]
想法一
既然是这类题目肯定是不能N个for循环去做了,螺旋地把矩阵转化成链表,其步骤一共就四步:向左->向下->向右->向上,然后再进行循环。那么我们只需要定义出这四个函数,同时在每个函数内判断出啥时候该转弯(边际条件)就行了。
代码:
public class Solution {
/**
* @param matrix a matrix of m x n elements
* @return an integer list
*/
public List<Integer> spiralOrder(int[][] matrix) {
// Write your code here
List<Integer> ret = new ArrayList<Integer>() ;
if(matrix.length == 0)
{
return ret;
}
int size = (matrix.length) *(matrix[0].length);
int n = 1;
while(ret.size() != size)
{
ret.addAll(onesplit(matrix , n));
ret.addAll(twosplit(matrix , n));
ret.addAll(threesplit(matrix ,n));
ret.addAll(foursplit(matrix , n));
n++;
}
return ret;
}
public List<Integer> onesplit(int [][] matrix , int n) { //(0,0) - > (0,4)
List<Integer> ret = new ArrayList<Integer>() ;
int limit = matrix[0].length -n + 1;
for (int i = n-1 ; i < limit ; i++) {
ret.add(matrix[n-1][i]);
}
return ret;
}
public List<Integer> twosplit(int [][] matrix , int n) {//(1,4) - > (4,4)
List<Integer> ret = new ArrayList<Integer>() ;
int limit = matrix.length - n + 1 ;
for (int i = n ; i < limit; i++) {
ret.add(matrix[i][matrix[0].length - n]);
}
return ret;
}
public List<Integer> threesplit(int [][] matrix , int n) { //(4,3) - > (4,0)
List<Integer> ret = new ArrayList<Integer>() ;
int start = matrix[0].length - n -1 ;
for (int i = start; i >= n-1 ; i--) {
ret.add(matrix[matrix.length - n ][i]);
}
return ret;
}
public List<Integer> foursplit(int [][] matrix , int n) {//(3,0) - > (1,0)
List<Integer> ret = new ArrayList<Integer>() ;
int start = matrix.length - n -1 ;
for (int i = start; i >= n ; i--) {
ret.add(matrix[i][n-1]);
}
return ret;
}
}
整体思路就是依次向四个方向走,每次走到该转向的时候都把这个方向的最长路径减一,这样就能走出螺旋了。
想法很好,思考一下复杂度也应该是O(N)吧,但是Submit后给我返回了个“TLE”
既然TLE了,这个算法肯定是不行的,换个思路吧。
想法二
我们还是假装在一个矩阵上走路,不过现在我们一次只走一格,每走一格我们都去想有没有走到“头”,如果到头了就转向吧,同时每次转向将下次走这个方向的“头”的数值-1
代码实现如下:
public class Solution {
/**
* @param matrix a matrix of m x n elements
* @return an integer list
*/
public List<Integer> spiralOrder(int[][] matrix) {
// Write your code here
List<Integer> ret = new LinkedList<Integer> ();
if(matrix.length == 0)
{
return ret;
}
int m = 0;
int n = 0;
int flag = 0;
int limit_1 = matrix.length -1; //竖着的
int limit_2 = matrix[0].length -1; //横着的
int size = matrix.length * matrix[0].length;
int limit_3 = 1;//竖着的
int limit_4 = 0;//横着的
while(ret.size()!=size)
{
ret.add(matrix[m][n]);
if(flag == 0){
//横着往右走
if( n == limit_2){
flag = 1;
limit_2--;
m++;
continue;
}
n++;
}
else if(flag == 1){
//竖着往下走
if( m == limit_1){
flag = 2;
limit_1--;
n--;
continue;
}
m++;
}
else if(flag == 2){
//横着往左走
if( n == limit_4){
flag = 3;
limit_4++;
m--;
continue;
}
n--;
}
else if(flag == 3){
//竖着往上走
if(m == limit_3){
flag = 0;
limit_3++;
n++;
continue;
}
m--;
}
}
return ret;
}
}
然后果然AC了,还是蛮开心的,通过把两个循环拆成一个成功解决了TLE的问题,不过代码中很多IF判断其实应该用switch,不够简洁。
希望能遇上更多的TLE加深我对算法思路的认识