剑指offer 19. 顺时针打印矩阵 & leetcode 剑指 Offer 29. 顺时针打印矩阵 & 螺旋矩阵 (Java/Golang)
19. 顺时针打印矩阵
题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
思路:
链接:https://www.nowcoder.com/questionTerminal/9b4c81a02cd34f76be2659fa0d54342a?answerType=1&f=discussion
定义四个变量代表范围,up、down、left、right
1. 向右走存入整行的值,当存入后,该行再也不会被遍历,代表上边界的 up 加一,同时判断是否和代表下边界的 down 交错
2. 向下走存入整列的值,当存入后,该列再也不会被遍历,代表右边界的 right 减一,同时判断是否和代表左边界的 left 交错
3. 向左走存入整行的值,当存入后,该行再也不会被遍历,代表下边界的 down 减一,同时判断是否和代表上边界的 up 交错
4. 向上走存入整列的值,当存入后,该列再也不会被遍历,代表左边界的 left 加一,同时判断是否和代表右边界的 right 交错
1 import java.util.ArrayList; 2 public class Solution { 3 public ArrayList<Integer> printMatrix(int [][] matrix) { 4 // 判断矩阵是否为空 5 ArrayList<Integer> list = new ArrayList<>(); 6 int up = 0, down = matrix.length - 1; 7 int left = 0, right = matrix[0].length - 1; 8 if(matrix == null || down < 0 || left < 0){ 9 return list; 10 } 11 12 // 四个方向遍历矩阵, 动态更新四个边界值 13 int col, row; 14 while(true){ 15 // 最上面这行向右 16 for(col = left; col <= right; col++){ 17 list.add(matrix[up][col]); 18 } 19 up++; // 更新上边界 20 if(down < up){ 21 break; 22 } 23 // 最右边这行向下 24 for(row = up; row <= down; row++){ 25 list.add(matrix[row][right]); 26 } 27 right--; // 更新右边界 28 if(left > right){ 29 break; // 如果越界则跳出循环 30 } 31 // 最下面这行向左 32 for(col = right; col >= left; col--){ 33 list.add(matrix[down][col]); 34 } 35 down--; // 更新下边界 36 if(up > down){ 37 break; // 如果越界则跳出循环 38 } 39 // 最左边这行向上 40 for(row = down; row >= up; row--){ 41 list.add(matrix[row][left]); 42 } 43 left++; // 更新左边界 44 if(left > right){ 45 break; 46 } 47 } 48 return list; 49 } 50 }
leetcode运行时间为1ms - 96.82%, 空间为40.2MB - 37.45%
复杂度分析:
时间复杂度:遍历了整个矩阵,所以时间复杂度为O(rows*cols)
空间复杂度:除了存储结果的矩阵,其他的空间都是常量级的,所以空间复杂度为O(1)
Golang 写法
毕业后面试第一题算法题,今天面试被问到了这题,但是太久了没刷题了,而且对 golang 的二维数组遍历和长度获取不是很熟,导致捣鼓了很久也没写完,难过想哭😭😭😭
package main import "fmt" // 输出螺旋矩阵 func printMatrix(arr [][]int) { if arr == nil || len(arr) == 0 { return } // 左右边界和上下边界 leftBorder, rightBorder := 0, len(arr[0]) - 1 upBorder, downBorder := 0, len(arr) - 1 var i, j int for ; ; { // 从左往右遍历最上面那行 for j = leftBorder; j <= rightBorder; j++ { fmt.Printf("%v ", arr[upBorder][j]) } upBorder++ // 更新上边界 if upBorder > downBorder { // // 上边界超过下边界,越界直接结束循环 break } // 从上往下遍历最右边那行 for i = upBorder; i <= downBorder; i++ { fmt.Printf("%v ", arr[i][rightBorder]) } rightBorder-- // 更新右边界 if rightBorder < leftBorder { // // 右边界小于左边界,越界直接结束循环 break } // 从右往左遍历最下面那行 for j = rightBorder; j >= leftBorder; j-- { fmt.Printf("%v ", arr[downBorder][j]) } downBorder-- // 更新下边界 if downBorder < upBorder { // // 下边界小于上边界了,越界直接结束循环 break } // 从下往上遍历最左边那行 for i = downBorder; i >= upBorder; i-- { fmt.Printf("%v ", arr[i][leftBorder]) } leftBorder++ // 更新左边界 if leftBorder > rightBorder { // 左边界大于右边界,越界直接结束循环 break } } fmt.Printf("\n") }
测试 case 4个:正常二维数组,单行,单列,空数组
func main() { arr := [][]int{ {1, 2, 3, 4, 5}, {14, 15, 16, 17, 6}, {13, 20, 19, 18, 7}, {12, 11, 10, 9, 8}, } printMatrix(arr) // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 arr = [][]int{ {1, 2, 3, 4, 5}, } printMatrix(arr) // 1 2 3 4 5 arr = [][]int { {1}, {2}, {3}, {4}, {5}, } printMatrix(arr) // 1 2 3 4 5 arr = [][]int { } printMatrix(arr) // }