54.Spiral Matrix

来源:互联网 发布:上证指数数据下载 编辑:程序博客网 时间:2024/06/06 02:33

问题编号:
54. Spiral Matrix
Difficulty: Medium


问题描述:
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

For example,
Given the following matrix:

[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ]]

You should return [1,2,3,6,9,8,7,4,5].


问题分析:
题目要求螺旋遍历一个m×n矩阵,我的思路是:从某一行(列)第一个元素开始,先遍历这一行(列),到达边界后(这里的边界可能是实际边界,也可能是已访问的数),回退到上一个下标,并且转向,重复这个过程。

这就需要用到一个标记数组visited[m][n],一个转向标记turn。这里我的做法是,先移动下标,判断该下标是否越界或已访问:否,则将该下标下的数添加到结果链表,并标记为已访问;是,则回退到上一次访问的下标,并将turn+1,不改变visited数组。然后进入下一轮循环。循环结束的条件是:当前结果链表的长度等于矩阵的长×宽(m×n)。

解决方案比较常规,不是什么比较巧的方法。运行时间是3ms。


我的解决方案:

public List<Integer> spiralOrder(int[][] matrix) {    List<Integer> res = new ArrayList<>();    if(matrix.length == 0)  return res;    int m, n;    m = matrix.length;    n = matrix[0].length;    int total = m * n;    int visited[][] = new int[m][n];//访问标记    int turn=0;//转向标记    int i=0;//下标    int j=0;    while(res.size() != total){        switch (turn % 4) {        case 0://向右走            if(j>=n || visited[i][j] == 1){//已访问或到达边界,回退                j--;                turn++;                visited[i][j] = 0;                res.remove(res.size()-1);            }            else {//走得通,加入结果链表,标记访问,进入下轮循环                res.add(matrix[i][j]);                visited[i][j] = 1;                j++;            }            break;        case 1://向下走            if(i>=m || visited[i][j] == 1){                i--;                turn++;                visited[i][j] = 0;                res.remove(res.size()-1);            }            else {                res.add(matrix[i][j]);                visited[i][j] = 1;                i++;            }            break;        case 2://向左走            if(j<0 || visited[i][j] == 1){                j++;                turn++;                visited[i][j] = 0;                res.remove(res.size()-1);            }            else {                res.add(matrix[i][j]);                visited[i][j] = 1;                j--;            }            break;        case 3://向上走            if(i<0 || visited[i][j] == 1){                i++;                turn++;                visited[i][j] = 0;                res.remove(res.size()-1);            }            else {                res.add(matrix[i][j]);                visited[i][j] = 1;                i--;            }            break;        default://可以没有            break;        }    }    return res;    }

另外一个解决方法:
代码量少一些,用到的空间少一些,这里不需要转向标记,不需要visited访问标记。这里只需要一个边界标记。
然而速度并没有比上一个方法快。。。

public List<Integer> spiralOrder2(int[][] matrix){    List<Integer> res = new ArrayList<>();    if(matrix.length == 0)  return res;    int m, n;    m = matrix.length;    n = matrix[0].length;    int total = m * n;    int colPointer = 0;    int rowPointer = 0;    int edge=0;    while(true){        while(colPointer<n-edge){            res.add(matrix[rowPointer][colPointer]);//依次添加第“一”行元素,“一”是相对于每一层主循环而言            colPointer++;//指针向右移动一位        }        if(res.size()==total)   break;        rowPointer++;//因为第“一”行最后一个元素已经被访问,行指针也需要移动一位,否则会重复添加        colPointer--;//上面循环中多加了一次,这里需要减掉        while(rowPointer<m-edge){            res.add(matrix[rowPointer][colPointer]);            rowPointer++;        }        if(res.size()==total)   break;        colPointer--;        rowPointer--;        while(colPointer>=0+edge){            res.add(matrix[rowPointer][colPointer]);            colPointer--;        }        if(res.size()==total)   break;        rowPointer--;        colPointer++;        edge++;//因为第“一”行第一个元素已经被访问过,这里再次向上走之前,边界需要发生变化        while(rowPointer>=0+edge){            res.add(matrix[rowPointer][colPointer]);            rowPointer--;        }        if(res.size()==total)   break;        colPointer++;        rowPointer++;    }    return res;}
0 0
原创粉丝点击