如何更改此矩阵螺旋遍历的方向和起点?

时间:2014-01-14 08:16:30

标签: java arrays matrix traversal

我有一些代码(following this example)从左上角开始遍历矩阵并顺时针方向移动。我想在此基础上制作三种新方法:

  • 一个从左上角开始逆时针方向
  • 从中间开始顺时针方向
  • 从中间开始并逆时针走的

为了解决这些问题,我需要更改哪些内容?我试过反转计数器增量并改变开始/结束行/列没有成功。

public static void traverseSpiral(int[][] matrix) {

    if(matrix.length == 0|| matrix[0].length == 0) {
        return;
    }

    StringBuffer stringBuffer = new StringBuffer();
    int counter = matrix.length * matrix[0].length;
    int startRow = 0;
    int endRow = matrix.length-1;
    int startCol = 0;
    int endCol = matrix[0].length-1;
    boolean moveCol = true;
    boolean leftToRight = true;
    boolean upDown = true;

    while(counter>0) {
        if(moveCol) {
            if(leftToRight) {

            /* printing entire row left to right */
                for(int i = startCol; i <= endCol ; i++){
                    stringBuffer.append(matrix[startRow][i]);
                    counter--;
                }
                leftToRight = false;
                moveCol = false;
                startRow++;
            }
            else{

            /* printing entire row right to left */
                for(int i = endCol ; i >= startCol ; i--){
                    stringBuffer.append(matrix[endRow][i]);
                    counter--;
                }
                leftToRight = true;
                moveCol = false;
                endRow--;
            }
        }
        else
        {
            if(upDown){

            /* printing column up down */
                for(int i = startRow ; i <= endRow ; i++){
                    stringBuffer.append(matrix[i][endCol]);
                    counter--;
                }
                upDown = false;
                moveCol = true;
                endCol--;
            }
            else
            {

            /* printing entire col down up */
                for(int i = endRow ; i >= startRow ; i--){
                    stringBuffer.append(matrix[i][startCol]);
                    counter--;
                }
                upDown = true;
                moveCol = true;
                startCol++;
            }
        }
    }
    System.out.println(stringBuffer.toString());
}

3 个答案:

答案 0 :(得分:2)

您的代码的问题在于您将其全部转储到一个方法中,使您的代码非常难以阅读并且更难以修改(不会破坏任何内容)。

由于这是针对面试问题,您应该努力不仅找到解决方案,而且找到最优雅的解决方案。或者最快的解决方案。或者最短的。最终,每个程序员在代码方面都有不同的优先级。但大多数(如果不是所有程序员)都努力编写好的代码

优秀代码易于阅读,编写和维护。虽然没有关于什么是优秀代码的确切定义,但克里斯托弗·约翰逊发布了this answer,我认为它能够很好地涵盖基本要素。

考虑将代码分解为单独的方法,每个方法都有自己的责任。马上,我可以看到四个代码块应该是他们自己的方法(从左到右,从右到左,从上到下,从下到上打印)。这将使您的代码更清晰。

例如,在这个问题的递归解决方案中,我至少有5个方法:

// A method that will handle the traversal of the spiral.
public static String clockwise(int[][] matrix);

// Responsible for printing a column from bottom to top.
public static String up(int[][] matrix, int first, int last);

// Responsible for printing a column from top to bottom.
public static String down(int[][] matrix, int first, int last);

// Responsible for printing a column from right to left.
public static String left(int[][] matrix, int first, int last);

// Responsible for printing a column from left to right.
public static String right(int[][] matrix, int first, int last);

使用这些方法,实现一种逆时针遍历相同螺旋的方法就像编写另一种重用up(matrix, first, last)down(matrix, first, last)left(matrix, first, last)&amp;的代码的方法一样简单。 right(matrix, first, last)因为:

Clockwise          = right, down, left, up;
Counter-Clockwise  = down, right, up, left;

就个人而言,我更喜欢divide-and-conquer递归方法。由于在大小为3x3的网格周围进行螺旋形旋转与在2x2的网格周围进行一次额外一圈的旋转基本相同,因此您可以使用递归来查找&amp;解决问题的最小版本,并按步骤构建解决方案。

我强烈建议你研究一下递归和分数&amp;独立征服方法。如果您只是对解决螺旋遍历问题感兴趣,包括顺时针,逆时针,顺时针向外和逆时针向外,请参阅GitHub Gist here

注意:上面的代码是原样,不保证任何种类。所以请注意。

答案 1 :(得分:1)

需要实现三种方法:

  1. 从左上角开始逆时针方向

  2. 从中间开始顺时针方向

  3. 从中间开始并逆时针走的

  4. 让我们谈谈第一个(你实现它)

    我们采用3x3矩阵

    +---+---+---+  
    |   |   |   |
    +---+---+---+  
    |   |   |   |
    +---+---+---+  
    |   |   |   |
    +---+---+---+
    

    因此,对于您的实现,它应该是

    SR=0, ER=2, SC=0, EC=2
    
    (SR: startRow, ER: endRow, SC: startCol, EC: endCol)
    
    SC->EC 
    SR++   (=>SR=1)
    SR->ER 
    EC--   (=>EC=1)
    EC->SC 
    ER--   (=>ER=1)
    ER->SR
    SC++   (=>SC=1)
    SC->EC
    -> finish with (SR=1,ER=1,SC=1,EC=1)
    

    让我们扭转它,所以它成为第三个。

    SR=1, ER=1, SC=1, EC=1
    EC->SC
    SC--
    SR->ER
    ER++
    SC->EC
    EC++
    ER->SR
    SR--
    EC->SC
    -> finish with (SR=0,ER=2,SC=0,EC=2)
    

    因此,重点不仅要改变SR,ER,SC,EC的值,还要改变修改其值的位置。 一切都是颠倒的,所以向右走,即打印startCol就会打印endCol。其他方向相同。

    因此,

    if(leftToRight) {
    
    /* printing entire row left to right */
        for(int i = startCol; i <= endCol ; i++){
            stringBuffer.append(matrix[startRow][i]);
            counter--;
        }
        leftToRight = false;
        moveCol = false;
        startRow++;
    } 
    

    成为

    if (leftToRight) {
    
        /* printing entire row left to right */
        for (int i = startCol; i <= endCol; i++) {
            stringBuffer.append(matrix[endRow][i]);
            counter--;
        }
        leftToRight = false;
        moveCol = false;
        endCol++;
    } 
    

    其行#和列#为奇数的矩阵,您可以选择由(moveCol,leftRight,upDown)定义的任何起始方向。然而,矩阵的行#或列#是偶数,那么起始方向是显着的。

    +---+---+---+---+  
    |   |   |   |   |
    +---+---+---+---+  
    |   | P |   |   |
    +---+---+---+---+  
    |   |   |   |   |
    +---+---+---+---+  
    |   |   |   |   |
    +---+---+---+---+
    

    例如,对于4x4矩阵,如果起点是P(1,1)(startRow =(4-1)/ 2,startCol =(4-1)/ 2),那么只有一种方法可以进行螺旋运算逆时针(upDown = true,leftRight = true,moveCol = false)

    类似的方法可以应用于第二个问题

    if (leftToRight) {
    
        /* printing entire row left to right */
        for (int i = startCol; i <= endCol; i++) {
            stringBuffer.append(matrix[startRow][i]);
            counter--;
        }
        leftToRight = false;
        moveCol = false;
        endCol++;
    }
    

答案 2 :(得分:0)

这很简单,请参阅下面的解决方案:

class Region  {
    int left, right, top, bottom;
    Region(int _left, int _right, int _top, int_bottom) {
        left=_left;  right=_right;  top=_top;  bottom=_bottom; 
    }
    boolean isEmpty() { return (left>right || top>bottom); }
    boolean isSingleElement() { return (left==right && top==bottom); }
}

List<Coordinate> traverseClockWise(Region r) {
    List<Coordinate> l = new List<Coordinate>();
    if (r.isEmpty()) {
        return l; 
    }
    if (r.isSingleElement()) {
        l.add(new Coordinate(r.left, r.top));
        return l; 
    }

    for (int i=r.left; i<r.right; i++) {
        l.add(new Coordinate(i, r.top));
    }
    for (int i=r.top; i<r.bottom; i++) {
        l.add(new Coordinate(r.right, i));
    }
    for (int i=r.right; i>r.left; i--) {
        l.add(new Coordinate(i, r.bottom));
    }
    for (int i=r.bottom; i>r.top; i--) {
        l.add(new Coordinate(r.left, i));
    }

    l.addAll(traverseClockWise(new Region(r.left+1, r.right-1, r.top+1, rs.bottom-1)));
    return l;
}


void traverse(Matrix A, int row, int col)  {
}

void example() {
    //suppose A is the matrix you are given and n is the size of the matrix
    Matrix A = new Matrix(n,n);
    List<Coordinates> l = traverseClockWise(new Region(1, n, 1, n));

    // to traverse it from top left counterclockwise
    for (int i=0; i<l.size(); i++) {
        traverse(A, l[i].col, l[i].row);
    }

    // to traverse it from the middle and clockwise
    for (int i=l.size()-1; i>=0; i--) {
        traverse(A, l[i].col, l[i].row);
    }

    // to traverse it from the middle and counterclockwise
    for (int i=l.size()-1; i>=0; i--) {
        traverse(A, l[i].row, l[i].col);
    }
}