{"id":391378,"date":"2024-06-29T09:47:30","date_gmt":"2024-06-29T09:47:30","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=391378"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=391378","title":{"rendered":"<span>Algorithms in Go: Matrix Spiral<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Most solutions to algorithmic problems can be grouped into a rather small number of patterns. When we start to solve some problem, we need to think about how we would classify them. For example, can we apply <code>fast and slow<\/code>algorithmic pattern or do we need to use <code>cyclic sort<\/code>pattern? Some of the problems have several solutions with different patterns. In this article of series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go<\/a> we consider an algorithmic pattern that solves an entire class of the problems related to a matrix. Let&#8217;s take one of such problems and see how we can handle it.<\/p>\n<p>How can we traverse a matrix in a spiral order?<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/704\/91d\/dbf\/70491ddbf7f0f08ba0309160c96d06fa.jpg\" width=\"1352\" height=\"739\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/704\/91d\/dbf\/70491ddbf7f0f08ba0309160c96d06fa.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>We can start with the observation that we are simulating a clock-wise movement and we continue the movement until we exhaust the matrix. How many movements will we have in total? We need to traverse all matrix, therefore the total number of moves will be equal to the total numbers of cells. Ok, then we have a loop condition:<\/p>\n<pre><code class=\"go\">n := len(matrix)    \/\/ number of rows m := len(matrix[0]) \/\/ number of columns \/\/ iterate through all cells for i := 0; i &lt; n * m; i++{ } <\/code><\/pre>\n<p>What do we do inside the loop?<\/p>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/f77\/1ec\/5b0\/f771ec5b03bd6cf82428f32a3b84a984.jpg\" width=\"1113\" height=\"898\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f77\/1ec\/5b0\/f771ec5b03bd6cf82428f32a3b84a984.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>We start with the left movement:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/464\/aa9\/758\/464aa97589f285ad9cfb680faeef7a46.jpg\" width=\"1026\" height=\"973\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/464\/aa9\/758\/464aa97589f285ad9cfb680faeef7a46.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>We proceed to the left till we reach the right border of the array, and then change the direction to the downward movement.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/13e\/7db\/cdf\/13e7dbcdfd502ed410c610539e2c7709.jpg\" width=\"1167\" height=\"856\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/13e\/7db\/cdf\/13e7dbcdfd502ed410c610539e2c7709.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>We go down until we reach the bottom border and then start to move to the right.<\/p>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/980\/702\/5d3\/9807025d36e32b094975e08d14c1c933.jpg\" width=\"969\" height=\"1031\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/980\/702\/5d3\/9807025d36e32b094975e08d14c1c933.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>We reach the left border of the array and change the direction the last time and now move upwards.<\/p>\n<p>Let&#8217;s move \ud83d\ude42 :<\/p>\n<pre><code class=\"go\">row, col := 0, 0 for i := 0; i &lt; n * m; i++ {     value := matrix[row][col]     out = append(out, cell) \/\/ save the value     row, col = applyMove(row, col) \/\/ move to the next cell } <\/code><\/pre>\n<p>How do we apply to move? We have four possible moves:<\/p>\n<pre><code class=\"go\">\/\/ the first value represents the iteration by columns \/\/ the second value represents the iteration by rows   moves := [][]int{    {0, 1},  \/\/ move to the left column    {1, 0},  \/\/ move down to the lower row    {0, -1}, \/\/ move to the right column    {-1, 0}, \/\/ move to the upper row   } <\/code><\/pre>\n<p>If we didn&#8217;t reach the border we just continue the movement in the current direction. Otherwise, we need to change the move.<\/p>\n<p>When we select the next cell, i.e next <code>row<\/code> and <code>col<\/code> values, we check the borders and change the direction if necessary:<\/p>\n<pre><code class=\"go\">func applyMove(row, col int) (int, int) {     newRow := row + moves[move][0]     newCol := col + moves[move][1]     if newRow == -1 || newRow == n || newCol == -1 || newCol == m {        \/\/ change the direction        move = move + 1               newRow = row + moves[move][0]        newCol = col + moves[move][1]      }   return newRow, newCol <\/code><\/pre>\n<p>OK, now we can process the first layer of the matrix. How can we generalise the algorithm and process the whole matrix?<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/086\/810\/3dc\/0868103dc387ecd854e06e9115c2d17f.jpg\" width=\"1050\" height=\"951\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/086\/810\/3dc\/0868103dc387ecd854e06e9115c2d17f.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>We need to stop at the cell with value <code>1<\/code>, as we already consumed it, and start the new circle. How do we start the new circle? We change the direction and instead of moving upwards <code>5<\/code> \u2192 <code>1<\/code> we go to the left <code>5<\/code> \u2192 <code>6<\/code>. Therefore, we have a circle in a list of movements and we can help ourselves with a modulo operator:<\/p>\n<pre><code class=\"go\">move = (move + 1) % len(moves) <\/code><\/pre>\n<p>We also need to save all iterated cells and change the direction if we already processed the cell.<\/p>\n<pre><code class=\"go\"> seen[row][col] = true newRow := row + moves[move][0] newCol := col + moves[move][1] if newRow == -1 || newRow == n || newCol == -1 || newCol == m || seen[newRow][newCol] {  \/\/ change the direction  move = (move + 1) % len(moves)         row = row + moves[move][0]  col = col + moves[move][1]  } else {  row, col = newRow, newCol }  <\/code><\/pre>\n<p>Full listing:<\/p>\n<pre><code class=\"go\">func spiralOrder(matrix [][]int) (out []int){     if len(matrix) == 0 {     return out   }    n, m := len(matrix), len(matrix[0])      \/\/ processed cells   seen := make([][]bool, n)   for row := 0; row &lt; n; row++ {       seen[row] = make([]bool, m)     }    moves := [][]int{    {0, 1},  \/\/ move to the left column    {1, 0},  \/\/ move down to the lower row    {0, -1}, \/\/ move to the right column    {-1, 0}, \/\/ move to the upper row   }    row, col := 0, 0   move := 0      applyMove := func() {       seen[row][col] = true         newRow := row + moves[move][0]         newCol := col + moves[move][1]         if newRow == -1 || newRow == n || newCol == -1 || newCol == m || seen[newRow][newCol] {            \/\/ change the direction            move = (move + 1) % len(moves)                    row = row + moves[move][0]            col = col + moves[move][1]          } else {        row, col = newRow, newCol     }   }      for i := 0; i &lt; n * m; i++ {         value := matrix[row][col]     out = append(out, value)     row, col = applyMove()     }      return out } <\/code><\/pre>\n<p>What complexity do we have? We touch every cell only once, so the time complexity is <code>O(n*m)<\/code>. We have an auxiliary matrix <code>seen<\/code>, therefore our space complexity is also <code>O(n*m)<\/code>.<\/p>\n<p>Can we do better than that? We cannot improve the time complexity as we need to visit all the cells in any case. However, we can think of removing the auxiliary matrix <code>seen<\/code>.  As discussed above we have four movements: left, down, right, up. We need to find a way to limit the range of the movements so we don&#8217;t slip outside of the borders of the matrix and we don&#8217;t process the same cell twice. Let&#8217;s initialize the sentinels.<\/p>\n<pre><code class=\"go\">left := 0 right := m-1 top := 0 bottom := n-1 <\/code><\/pre>\n<p>We start with the left movement and iterate through all cells in the <code>top<\/code> row. After the iteration we increment <code>top<\/code> border, as the <code>top<\/code> row was fully consumed:<\/p>\n<pre><code class=\"go\">for col := left; col &lt;= right; col++ {     out = append(out, matrix[top][col]) } top++ <\/code><\/pre>\n<p>Then we go downwards and iterate through all rows from <code>top<\/code> (which is now equal to one) to <code>bottom<\/code> inclusive. In this movement we fully consume the <code>right<\/code> column, therefore we decrease the <code>right<\/code> border:<\/p>\n<pre><code class=\"go\">for row := top; row &lt;= bottom; row++ {     out = append(out, matrix[row][right]) } right-- <\/code><\/pre>\n<p>In the right movement, we consume all cells in the <code>bottom<\/code> row starting with the <code>right<\/code> column (which is now equal to last but one column) to the <code>left<\/code> column inclusive. After the iteration, we have fully consumed the <code>bottom<\/code> row and decrease the <code>bottom<\/code> border. Note that we go in the reversed direction, therefore we decrement the value of the current column after the iteration.<\/p>\n<pre><code class=\"go\">for col := right; col >= left; col-- {     out = append(out, matrix[bottom][col]) } bottom-- <\/code><\/pre>\n<p>Now, we close the circle and move upwards. We iterate through all the rows starting from the <code>bottom<\/code> (which is now equal to the last but one column) to the <code>top<\/code> row (which is now equal to the second row) inclusive. As in the previous movement, we go in the reverse direction and decrease the value of the current row. After the movement, we have fully consumed the <code>left<\/code> column and can increase the <code>left<\/code> counter.<\/p>\n<pre><code class=\"go\">for row := bottom; row >= top; row-- {     out = append(out, matrix[row][left]) } left++ <\/code><\/pre>\n<p>In this manner, we consume the first layer of the matrix. We continue the iteration till we exhaust the matrix. We need to stop when there are no more columns or no more rows left to process. When <code>left<\/code> becomes greater than <code>right,<\/code>  we have processed all the columns. When <code>top<\/code> becomes greater than <code>bottom<\/code> we have processed all the rows. In either of these two cases, we have no more cells to process. Therefore, our exit condition looks like the following:<\/p>\n<pre><code class=\"go\">for left &lt;= right &amp;&amp; top &lt;= bottom {     \/\/ left move     for col := left; col &lt;= right; col++ {         out = append(out, matrix[top][col])     }     top++    \/\/ downward move     for row := top; row &lt;= bottom; row++ {         out = append(out, matrix[row][right])     }     right--    \/\/ right move     for col := right; col >= left; col-- {         out = append(out, matrix[bottom][col])     }     bottom--    \/\/ upward move     for row := bottom; row >= top; row-- {         out = append(out, matrix[row][left])     }     left++ } <\/code><\/pre>\n<p>Let&#8217;s check some edge cases to verify that our algorithm works as intended.<\/p>\n<p>What happens if we deal with a matrix of a single row? Our left move consumes all the cells, our downward move will be no-op as <code>top<\/code> will be already larger than the <code>bottom<\/code>. However, our right movement causes the problem as it re-consumes the cells from the last row which is the same as the first row.<\/p>\n<p>In the same vein, in case of a matrix of a single column, our upward movement becomes redundant. Therefore, we need to prevent such movements by the if condition:<\/p>\n<pre><code class=\"go\">if left > right || top > bottom {     break } <\/code><\/pre>\n<p>Therefore, the full listing looks as the following:<\/p>\n<pre><code class=\"go\">left := 0 right := m-1 top := 0 bottom := n-1  for left &lt;= right &amp;&amp; top &lt;= bottom {     \/\/ left move     for col := left; col &lt;= right; col++ {         out = append(out, matrix[top][col])     }     top++    \/\/ downward move     for row := top; row &lt;= bottom; row++ {         out = append(out, matrix[row][right])     }     right--      if left > right || top > bottom {         break     }    \/\/ right move     for col := right; col >= left; col-- {         out = append(out, matrix[bottom][col])     }     bottom--    \/\/ upward move     for row := bottom; row >= top; row-- {         out = append(out, matrix[row][left])     }     left++ } <\/code><\/pre>\n<p>Now we have time and space complexity both equal to <code>O(n*m)<\/code>.<\/p>\n<p>We can use the same approach to the similar problems of matrix generation or matrix traversal.<\/p>\n<p>In this post, we implemented a solution for the Matrix Spiral problem. This is one of the most popular algorithmic patterns that solve an entire class of problems. More algorithmic patterns such as <a href=\"https:\/\/habr.com\/en\/post\/531444\/\" rel=\"noopener noreferrer nofollow\">Sliding Window<\/a> or <a href=\"https:\/\/habr.com\/en\/post\/545980\/\" rel=\"noopener noreferrer nofollow\">Iterative Postorder Traversal<\/a><a href=\"https:\/\/habr.com\/en\/post\/543618\/\" rel=\"noopener noreferrer nofollow\"> <\/a>can be found in the series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go.<\/a> <\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/543618\/\"> https:\/\/habr.com\/ru\/articles\/543618\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Most solutions to algorithmic problems can be grouped into a rather small number of patterns. When we start to solve some problem, we need to think about how we would classify them. For example, can we apply <code>fast and slow<\/code>algorithmic pattern or do we need to use <code>cyclic sort<\/code>pattern? Some of the problems have several solutions with different patterns. In this article of series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go<\/a> we consider an algorithmic pattern that solves an entire class of the problems related to a matrix. Let&#8217;s take one of such problems and see how we can handle it.<\/p>\n<p>How can we traverse a matrix in a spiral order?<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>We can start with the observation that we are simulating a clock-wise movement and we continue the movement until we exhaust the matrix. How many movements will we have in total? We need to traverse all matrix, therefore the total number of moves will be equal to the total numbers of cells. Ok, then we have a loop condition:<\/p>\n<pre><code class=\"go\">n := len(matrix)    \/\/ number of rows m := len(matrix[0]) \/\/ number of columns \/\/ iterate through all cells for i := 0; i &lt; n * m; i++{ } <\/code><\/pre>\n<p>What do we do inside the loop?<\/p>\n<figure class=\"bordered full-width\"><figcaption><\/figcaption><\/figure>\n<p>We start with the left movement:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>We proceed to the left till we reach the right border of the array, and then change the direction to the downward movement.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>We go down until we reach the bottom border and then start to move to the right.<\/p>\n<figure class=\"bordered full-width\"><figcaption><\/figcaption><\/figure>\n<p>We reach the left border of the array and change the direction the last time and now move upwards.<\/p>\n<p>Let&#8217;s move \ud83d\ude42 :<\/p>\n<pre><code class=\"go\">row, col := 0, 0 for i := 0; i &lt; n * m; i++ {     value := matrix[row][col]     out = append(out, cell) \/\/ save the value     row, col = applyMove(row, col) \/\/ move to the next cell } <\/code><\/pre>\n<p>How do we apply to move? We have four possible moves:<\/p>\n<pre><code class=\"go\">\/\/ the first value represents the iteration by columns \/\/ the second value represents the iteration by rows   moves := [][]int{    {0, 1},  \/\/ move to the left column    {1, 0},  \/\/ move down to the lower row    {0, -1}, \/\/ move to the right column    {-1, 0}, \/\/ move to the upper row   } <\/code><\/pre>\n<p>If we didn&#8217;t reach the border we just continue the movement in the current direction. Otherwise, we need to change the move.<\/p>\n<p>When we select the next cell, i.e next <code>row<\/code> and <code>col<\/code> values, we check the borders and change the direction if necessary:<\/p>\n<pre><code class=\"go\">func applyMove(row, col int) (int, int) {     newRow := row + moves[move][0]     newCol := col + moves[move][1]     if newRow == -1 || newRow == n || newCol == -1 || newCol == m {        \/\/ change the direction        move = move + 1               newRow = row + moves[move][0]        newCol = col + moves[move][1]      }   return newRow, newCol <\/code><\/pre>\n<p>OK, now we can process the first layer of the matrix. How can we generalise the algorithm and process the whole matrix?<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>We need to stop at the cell with value <code>1<\/code>, as we already consumed it, and start the new circle. How do we start the new circle? We change the direction and instead of moving upwards <code>5<\/code> \u2192 <code>1<\/code> we go to the left <code>5<\/code> \u2192 <code>6<\/code>. Therefore, we have a circle in a list of movements and we can help ourselves with a modulo operator:<\/p>\n<pre><code class=\"go\">move = (move + 1) % len(moves) <\/code><\/pre>\n<p>We also need to save all iterated cells and change the direction if we already processed the cell.<\/p>\n<pre><code class=\"go\"> seen[row][col] = true newRow := row + moves[move][0] newCol := col + moves[move][1] if newRow == -1 || newRow == n || newCol == -1 || newCol == m || seen[newRow][newCol] {  \/\/ change the direction  move = (move + 1) % len(moves)         row = row + moves[move][0]  col = col + moves[move][1]  } else {  row, col = newRow, newCol }  <\/code><\/pre>\n<p>Full listing:<\/p>\n<pre><code class=\"go\">func spiralOrder(matrix [][]int) (out []int){     if len(matrix) == 0 {     return out   }    n, m := len(matrix), len(matrix[0])      \/\/ processed cells   seen := make([][]bool, n)   for row := 0; row &lt; n; row++ {       seen[row] = make([]bool, m)     }    moves := [][]int{    {0, 1},  \/\/ move to the left column    {1, 0},  \/\/ move down to the lower row    {0, -1}, \/\/ move to the right column    {-1, 0}, \/\/ move to the upper row   }    row, col := 0, 0   move := 0      applyMove := func() {       seen[row][col] = true         newRow := row + moves[move][0]         newCol := col + moves[move][1]         if newRow == -1 || newRow == n || newCol == -1 || newCol == m || seen[newRow][newCol] {            \/\/ change the direction            move = (move + 1) % len(moves)                    row = row + moves[move][0]            col = col + moves[move][1]          } else {        row, col = newRow, newCol     }   }      for i := 0; i &lt; n * m; i++ {         value := matrix[row][col]     out = append(out, value)     row, col = applyMove()     }      return out } <\/code><\/pre>\n<p>What complexity do we have? We touch every cell only once, so the time complexity is <code>O(n*m)<\/code>. We have an auxiliary matrix <code>seen<\/code>, therefore our space complexity is also <code>O(n*m)<\/code>.<\/p>\n<p>Can we do better than that? We cannot improve the time complexity as we need to visit all the cells in any case. However, we can think of removing the auxiliary matrix <code>seen<\/code>.  As discussed above we have four movements: left, down, right, up. We need to find a way to limit the range of the movements so we don&#8217;t slip outside of the borders of the matrix and we don&#8217;t process the same cell twice. Let&#8217;s initialize the sentinels.<\/p>\n<pre><code class=\"go\">left := 0 right := m-1 top := 0 bottom := n-1 <\/code><\/pre>\n<p>We start with the left movement and iterate through all cells in the <code>top<\/code> row. After the iteration we increment <code>top<\/code> border, as the <code>top<\/code> row was fully consumed:<\/p>\n<pre><code class=\"go\">for col := left; col &lt;= right; col++ {     out = append(out, matrix[top][col]) } top++ <\/code><\/pre>\n<p>Then we go downwards and iterate through all rows from <code>top<\/code> (which is now equal to one) to <code>bottom<\/code> inclusive. In this movement we fully consume the <code>right<\/code> column, therefore we decrease the <code>right<\/code> border:<\/p>\n<pre><code class=\"go\">for row := top; row &lt;= bottom; row++ {     out = append(out, matrix[row][right]) } right-- <\/code><\/pre>\n<p>In the right movement, we consume all cells in the <code>bottom<\/code> row starting with the <code>right<\/code> column (which is now equal to last but one column) to the <code>left<\/code> column inclusive. After the iteration, we have fully consumed the <code>bottom<\/code> row and decrease the <code>bottom<\/code> border. Note that we go in the reversed direction, therefore we decrement the value of the current column after the iteration.<\/p>\n<pre><code class=\"go\">for col := right; col >= left; col-- {     out = append(out, matrix[bottom][col]) } bottom-- <\/code><\/pre>\n<p>Now, we close the circle and move upwards. We iterate through all the rows starting from the <code>bottom<\/code> (which is now equal to the last but one column) to the <code>top<\/code> row (which is now equal to the second row) inclusive. As in the previous movement, we go in the reverse direction and decrease the value of the current row. After the movement, we have fully consumed the <code>left<\/code> column and can increase the <code>left<\/code> counter.<\/p>\n<pre><code class=\"go\">for row := bottom; row >= top; row-- {     out = append(out, matrix[row][left]) } left++ <\/code><\/pre>\n<p>In this manner, we consume the first layer of the matrix. We continue the iteration till we exhaust the matrix. We need to stop when there are no more columns or no more rows left to process. When <code>left<\/code> becomes greater than <code>right,<\/code>  we have processed all the columns. When <code>top<\/code> becomes greater than <code>bottom<\/code> we have processed all the rows. In either of these two cases, we have no more cells to process. Therefore, our exit condition looks like the following:<\/p>\n<pre><code class=\"go\">for left &lt;= right &amp;&amp; top &lt;= bottom {     \/\/ left move     for col := left; col &lt;= right; col++ {         out = append(out, matrix[top][col])     }     top++    \/\/ downward move     for row := top; row &lt;= bottom; row++ {         out = append(out, matrix[row][right])     }     right--    \/\/ right move     for col := right; col >= left; col-- {         out = append(out, matrix[bottom][col])     }     bottom--    \/\/ upward move     for row := bottom; row >= top; row-- {         out = append(out, matrix[row][left])     }     left++ } <\/code><\/pre>\n<p>Let&#8217;s check some edge cases to verify that our algorithm works as intended.<\/p>\n<p>What happens if we deal with a matrix of a single row? Our left move consumes all the cells, our downward move will be no-op as <code>top<\/code> will be already larger than the <code>bottom<\/code>. However, our right movement causes the problem as it re-consumes the cells from the last row which is the same as the first row.<\/p>\n<p>In the same vein, in case of a matrix of a single column, our upward movement becomes redundant. Therefore, we need to prevent such movements by the if condition:<\/p>\n<pre><code class=\"go\">if left > right || top > bottom {     break } <\/code><\/pre>\n<p>Therefore, the full listing looks as the following:<\/p>\n<pre><code class=\"go\">left := 0 right := m-1 top := 0 bottom := n-1  for left &lt;= right &amp;&amp; top &lt;= bottom {     \/\/ left move     for col := left; col &lt;= right; col++ {         out = append(out, matrix[top][col])     }     top++    \/\/ downward move     for row := top; row &lt;= bottom; row++ {         out = append(out, matrix[row][right])     }     right--      if left > right || top > bottom {         break     }    \/\/ right move     for col := right; col >= left; col-- {         out = append(out, matrix[bottom][col])     }     bottom--    \/\/ upward move     for row := bottom; row >= top; row-- {         out = append(out, matrix[row][left])     }     left++ } <\/code><\/pre>\n<p>Now we have time and space complexity both equal to <code>O(n*m)<\/code>.<\/p>\n<p>We can use the same approach to the similar problems of matrix generation or matrix traversal.<\/p>\n<p>In this post, we implemented a solution for the Matrix Spiral problem. This is one of the most popular algorithmic patterns that solve an entire class of problems. More algorithmic patterns such as <a href=\"https:\/\/habr.com\/en\/post\/531444\/\" rel=\"noopener noreferrer nofollow\">Sliding Window<\/a> or <a href=\"https:\/\/habr.com\/en\/post\/545980\/\" rel=\"noopener noreferrer nofollow\">Iterative Postorder Traversal<\/a><a href=\"https:\/\/habr.com\/en\/post\/543618\/\" rel=\"noopener noreferrer nofollow\"> <\/a>can be found in the series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go.<\/a> <\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/543618\/\"> https:\/\/habr.com\/ru\/articles\/543618\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-391378","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/391378","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=391378"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/391378\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=391378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=391378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=391378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}