Search code examples
javaarraysmatrixtraversal

How do I change the directions and starting points of this matrix spiral traversal?


I have some code (following this example) to traverse a matrix starting from the upper left and going clockwise. I want to make three new methods based off of this:

  • One that starts from the top left and goes counterclockwise
  • One that starts from the middle and goes clockwise
  • One that starts from the middle and goes counterclockwise

What do I need to change for each of these to work? I've tried reversing the counter increments and changing the start/end row/columns with no success.

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());
}

Solution

  • The problem with your code is that you dumped it all into one method, making your code very difficult to read and more difficult to modify (without breaking anything).

    Since this is for an interview question, you should be striving to not just find the solution, but finding the most elegant solution. Or the fastest solution. Or the shortest. Ultimately, every programmer has different priorities when it comes to code. But most (if not all programmers) strive to write good code.

    Good code is easy to read, write and maintain. Although there is no exact definition of what makes good code, Kristopher Johnson posted this answer which I feel does a good job of covering the essentials.

    Consider breaking your code up into individual methods, each with their own responsibility. Right away, I can see four code blocks that should be their own methods (printing left to right, right to left, top to bottom and bottom to top). This will make your code much cleaner.

    For example, in a recursive solution to this problem, I would have at least 5 methods:

    // 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);
    

    With methods like those, implementing a method to traverse the same spiral counter-clockwise would be a simple as writing another method that reuses code from up(matrix, first, last), down(matrix, first, last), left(matrix, first, last) & right(matrix, first, last) since:

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

    Personally, I prefer a divide-and-conquer recursive approach. Since spiralling around a grid of size 3x3 is essentially the same as spiralling around a grid of 2x2 with one extra lap, you can use recursion to find & solve the smallest version of your problem and build up in steps to your solution.

    I'd strongly recommend that you look into recursion and the divide & conquer approach independently. If you're just interested in a solution to your spiral traversal problem, including clockwise, counter-clockwise, clockwise outwards and counter-clockwise outwards, see the GitHub Gist here.

    Note: The code above is provided as-is, without any guarantees of any kind. So be warned.