Here is a problem where the challenge lies solely in correct index handling: given a NxM matrix (could be square) return an array which is the result of a clockwise spiral visit from top left corner.
Example:
12
34
result = 1,2,4,3
The problem description itself is the solution, we simply need to correctly set boundaries for our visit and process all elements in the matrix.
This is another exercise where drawing out a sample greatly helps with handling those boundary cases, I think the smallest sample that shows the correct logic is a 3x3 matrix.
We can view the matrix as a series of arrays wrapped around each other, and we process one of them each time.
We can do this in O(NM) time and O(1) space using 4 indices, representing the current boundaries:
- start row: indicates the top boundary of the matrix we are processing
- end row: indicates the bottom boundary of the matrix we are processing
- start col: indicates the left boundary of the matrix we are processing
- end col: indicates the right boundary of the matrix we are processing
By making our indices inclusive we have an easier time handling the logic. This means a boundary index indicates the first or last element we want to add (no out of bounds handling necessary)
Initially our boundaries are:
- start row: 0 (top row)
- end row: matrix.length - 1 (bottom row)
- start col: 0 (left col)
- end col: matrix[0].length - 1 (right col)
Then, until we have added all elements in the matrix to our result, we execute 4 loops in succession, each processing one of the four boundaries.
When each of these loops end, we update the boundaries for the next.
We walk the matrix in a spiral and always add the bounds working our way inside:
- all of top: start row (left right) but start from NEXT column since we already added the first row element before (is first of column we just processed). NOTE: at the very beginning we already are on the correct position for this row so we only update the column AFTER all other boundaries have been processed
- add all of right: end column (top down) but start from NEXT row since we already added the first column element before (is last of row we just processed)
- add all of bottom: end row (right left) but start from PREVIOUS column since we already added the last row element before (is last of column we just processed)
- add all of left: start column (bottom up) but start from PREVIOUS row since we already added the last column element before (is first of row we just processed)
We can see that we need to move only ONE boundary after each loop by drawing a 3x3 matrix and executing this logic on it.
We can also see that while we do have 4 loops within one outer loop, we are only processing each element once.
You can check my implementation of spiralVisit on my Gist along with some tests in SpiralVisitJTests.
No comments:
Post a Comment
With great power comes great responsibility