29. 顺时针打印矩阵


comments: true
difficulty: 简单
edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9829.%20%E9%A1%BA%E6%97%B6%E9%92%88%E6%89%93%E5%8D%B0%E7%9F%A9%E9%98%B5/README.md

面试题 29. 顺时针打印矩阵

题目描述

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

 

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

 

限制:

  • 0 <= matrix.length <= 100
  • 0 <= matrix[i].length <= 100

注意:本题与主站 54 题相同:https://leetcode.cn/problems/spiral-matrix/

解法

方法一:模拟

我们用 i i i j j j 分别表示当前访问到的元素的行和列,用 k k k 表示当前的方向,用数组或哈希表 v i s vis vis 记录每个元素是否被访问过。每次我们访问到一个元素后,将其标记为已访问,然后按照当前的方向前进一步,如果前进一步后发现越界或者已经访问过,则改变方向继续前进,直到遍历完整个矩阵。

时间复杂度 O ( m × n ) O(m \times n) O(m×n),空间复杂度 O ( m × n ) O(m \times n) O(m×n)。其中 m m m n n n 分别是矩阵的行数和列数。

Python3
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return []
        dirs = (0, 1, 0, -1, 0)
        m, n = len(matrix), len(matrix[0])
        vis = [[False] * n for _ in range(m)]
        ans = []
        i = j = k = 0
        for _ in range(m * n):
            ans.append(matrix[i][j])
            vis[i][j] = True
            x, y = i + dirs[k], j + dirs[k + 1]
            if x < 0 or y < 0 or x >= m or y >= n or vis[x][y]:
                k = (k + 1) % 4
                x, y = i + dirs[k], j + dirs[k + 1]
            i, j = x, y
        return ans
Java
class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length == 0 || matrix[0].length == 0) {
            return new int[] {};
        }
        int m = matrix.length, n = matrix[0].length;
        boolean[][] vis = new boolean[m][n];
        int[] ans = new int[m * n];
        int i = 0, j = 0, k = 0;
        int[] dirs = {0, 1, 0, -1, 0};
        for (int h = 0; h < m * n; ++h) {
            ans[h] = matrix[i][j];
            vis[i][j] = true;
            int x = i + dirs[k], y = j + dirs[k + 1];
            if (x < 0 || y < 0 || x >= m || y >= n || vis[x][y]) {
                k = (k + 1) % 4;
                x = i + dirs[k];
                y = j + dirs[k + 1];
            }
            i = x;
            j = y;
        }
        return ans;
    }
}
C++
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return {};
        }
        int m = matrix.size(), n = matrix[0].size();
        bool vis[m][n];
        memset(vis, false, sizeof vis);
        int i = 0, j = 0, k = 0;
        int dirs[5] = {0, 1, 0, -1, 0};
        vector<int> ans(m * n);
        for (int h = 0; h < m * n; ++h) {
            ans[h] = matrix[i][j];
            vis[i][j] = true;
            int x = i + dirs[k], y = j + dirs[k + 1];
            if (x < 0 || y < 0 || x >= m || y >= n || vis[x][y]) {
                k = (k + 1) % 4;
                x = i + dirs[k];
                y = j + dirs[k + 1];
            }
            i = x;
            j = y;
        }
        return ans;
    }
};
Go
func spiralOrder(matrix [][]int) []int {
	if len(matrix) == 0 || len(matrix[0]) == 0 {
		return []int{}
	}
	m, n := len(matrix), len(matrix[0])
	vis := make([][]bool, m)
	for i := range vis {
		vis[i] = make([]bool, n)
	}
	i, j, k := 0, 0, 0
	dirs := [5]int{0, 1, 0, -1, 0}
	ans := make([]int, m*n)
	for h := 0; h < m*n; h++ {
		ans[h] = matrix[i][j]
		vis[i][j] = true
		x, y := i+dirs[k], j+dirs[k+1]
		if x < 0 || y < 0 || x >= m || y >= n || vis[x][y] {
			k = (k + 1) % 4
			x, y = i+dirs[k], j+dirs[k+1]
		}
		i, j = x, y
	}
	return ans
}
TypeScript
var spiralOrder = (matrix: number[][]): number[] => {
    let ans: number[] = [];
    if (matrix.length === 0) return ans;
    let top = 0,
        left = 0,
        bottom = matrix.length - 1,
        right = matrix[0].length - 1;
    while (true) {
        for (let i = left; i <= right; i++) ans.push(matrix[top][i]);
        top++;
        if (top > bottom) break;
        for (let i = top; i <= bottom; i++) ans.push(matrix[i][right]);
        right--;
        if (right < left) break;
        for (let i = right; i >= left; i--) ans.push(matrix[bottom][i]);
        bottom--;
        if (bottom < top) break;
        for (let i = bottom; i >= top; i--) ans.push(matrix[i][left]);
        left++;
        if (left > right) break;
    }
    return ans;
};
Rust
impl Solution {
    pub fn spiral_order(matrix: Vec<Vec<i32>>) -> Vec<i32> {
        let mut ans = Vec::new();
        if matrix.len() == 0 {
            return ans;
        }
        let (mut left, mut right, mut top, mut bottom) =
            (0, matrix[0].len() - 1, 0, matrix.len() - 1);
        loop {
            for i in left..right + 1 {
                ans.push(matrix[top][i]);
            }
            top += 1;
            if (top as i32) > (bottom as i32) {
                break;
            }
            for i in top..bottom + 1 {
                ans.push(matrix[i][right]);
            }
            right -= 1;
            if (right as i32) < (left as i32) {
                break;
            }
            for i in (left..right + 1).rev() {
                ans.push(matrix[bottom][i]);
            }
            bottom -= 1;
            if (bottom as i32) < (top as i32) {
                break;
            }
            for i in (top..bottom + 1).rev() {
                ans.push(matrix[i][left]);
            }
            left += 1;
            if (left as i32) > (right as i32) {
                break;
            }
        }
        ans
    }
}
JavaScript
/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function (matrix) {
    const ans = [];
    if (matrix.length == 0 || matrix[0].length == 0) {
        return ans;
    }
    const m = matrix.length;
    const n = matrix[0].length;
    let [top, bottom, left, right] = [0, m - 1, 0, n - 1];
    while (top <= bottom && left <= right) {
        for (let j = left; j <= right; ++j) {
            ans.push(matrix[top][j]);
        }
        for (let i = top + 1; i <= bottom; ++i) {
            ans.push(matrix[i][right]);
        }
        if (left < right && top < bottom) {
            for (let j = right - 1; j >= left; --j) {
                ans.push(matrix[bottom][j]);
            }
            for (let i = bottom - 1; i > top; --i) {
                ans.push(matrix[i][left]);
            }
        }
        [top, bottom, left, right] = [top + 1, bottom - 1, left + 1, right - 1];
    }
    return ans;
};
C#
public class Solution {
    public int[] SpiralOrder(int[][] matrix) {
        List<int> ans = new List<int>();
        if (matrix.Length == 0) {
            return ans.ToArray();
        }
        int left = 0, top = 0, bottom = matrix.Length - 1, right = matrix[0].Length - 1;
        while (true) {
            for (int i = left; i <= right; i++) {
                ans.Add(matrix[top][i]);
            }
            top += 1;
            if (top > bottom) {
                break;
            }
            for (int i = top; i <= bottom; i++) {
                ans.Add(matrix[i][right]);
            }
            right -= 1;
            if (right < left) {
                break;
            }
            for (int i = right; i >= left; i--) {
                ans.Add(matrix[bottom][i]);
            }
            bottom -= 1;
            if (bottom < top) {
                break;
            }
            for (int i = bottom; i >= top; i--) {
                ans.Add(matrix[i][left]);
            }
            left += 1;
            if (left > right) {
                break;
            }
        }
        return ans.ToArray();
    }
}
Swift
class Solution {
    func spiralOrder(_ matrix: [[Int]]) -> [Int] {
        guard !matrix.isEmpty && !matrix[0].isEmpty else {
            return []
        }

        let m = matrix.count
        let n = matrix[0].count
        var vis = Array(repeating: Array(repeating: false, count: n), count: m)
        var ans = [Int]()
        var i = 0, j = 0, k = 0
        let dirs = [0, 1, 0, -1, 0]

        for _ in 0..<m*n {
            ans.append(matrix[i][j])
            vis[i][j] = true
            var x = i + dirs[k], y = j + dirs[k + 1]
            if x < 0 || y < 0 || x >= m || y >= n || vis[x][y] {
                k = (k + 1) % 4
                x = i + dirs[k]
                y = j + dirs[k + 1]
            }
            i = x
            j = y
        }

        return ans
    }
}

方法二:逐层模拟

从外往里一圈一圈遍历并存储矩阵元素即可。

时间复杂度 O ( m × n ) O(m \times n) O(m×n),空间复杂度 O ( 1 ) O(1) O(1)。其中 m m m n n n 分别是矩阵的行数和列数。

Python3

注意:比较下面两段代码区别(变量的更新方式不同)

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return []
        m, n = len(matrix), len(matrix[0])
        ans = []
        top, bottom, left, right = 0, m - 1, 0, n - 1
        while left <= right and top <= bottom:
            ans.extend([matrix[top][j] for j in range(left, right + 1)])
            ans.extend([matrix[i][right] for i in range(top + 1, bottom + 1)])
            if left < right and top < bottom:
                ans.extend([matrix[bottom][j] for j in range(right - 1, left - 1, -1)])
                ans.extend([matrix[i][left] for i in range(bottom - 1, top, -1)])
            top, bottom, left, right = top + 1, bottom - 1, left + 1, right - 1
        return ans


def spiralOrder(matrix):
    if not matrix or not matrix[0]:
        return []
    
    m, n = len(matrix), len(matrix[0])
    ans = []
    top, bottom, left, right = 0, m - 1, 0, n - 1
    
    while left <= right and top <= bottom:
        # 从左到右遍历上边界
        for j in range(left, right + 1):
            ans.append(matrix[top][j])
        top += 1
        
        # 从上到下遍历右边界
        for i in range(top, bottom + 1):
            ans.append(matrix[i][right])
        right -= 1
        
        if top <= bottom:
            # 从右到左遍历下边界
            for j in range(right, left - 1, -1):
                ans.append(matrix[bottom][j])
            bottom -= 1
        
        if left <= right:
            # 从下到上遍历左边界
            for i in range(bottom, top - 1, -1):
                ans.append(matrix[i][left])
            left += 1
    
    return ans

Java
class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length == 0 || matrix[0].length == 0) {
            return new int[] {};
        }
        int m = matrix.length, n = matrix[0].length;
        int top = 0, bottom = m - 1, left = 0, right = n - 1;
        int[] ans = new int[m * n];
        int k = 0;
        while (left <= right && top <= bottom) {
            for (int j = left; j <= right; ++j) {
                ans[k++] = matrix[top][j];
            }
            for (int i = top + 1; i <= bottom; ++i) {
                ans[k++] = matrix[i][right];
            }
            if (left < right && top < bottom) {
                for (int j = right - 1; j >= left; --j) {
                    ans[k++] = matrix[bottom][j];
                }
                for (int i = bottom - 1; i > top; --i) {
                    ans[k++] = matrix[i][left];
                }
            }
            ++top;
            --bottom;
            ++left;
            --right;
        }
        return ans;
    }
}
C++
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return {};
        }
        int m = matrix.size(), n = matrix[0].size();
        int top = 0, bottom = m - 1, left = 0, right = n - 1;
        vector<int> ans;
        while (top <= bottom && left <= right) {
            for (int j = left; j <= right; ++j) ans.push_back(matrix[top][j]);
            for (int i = top + 1; i <= bottom; ++i) ans.push_back(matrix[i][right]);
            if (left < right && top < bottom) {
                for (int j = right - 1; j >= left; --j) ans.push_back(matrix[bottom][j]);
                for (int i = bottom - 1; i > top; --i) ans.push_back(matrix[i][left]);
            }
            ++top;
            --bottom;
            ++left;
            --right;
        }
        return ans;
    }
};
Go
func spiralOrder(matrix [][]int) []int {
	if len(matrix) == 0 || len(matrix[0]) == 0 {
		return []int{}
	}
	m, n := len(matrix), len(matrix[0])
	ans := make([]int, 0, m*n)

	top, bottom, left, right := 0, m-1, 0, n-1
	for left <= right && top <= bottom {
		for i := left; i <= right; i++ {
			ans = append(ans, matrix[top][i])
		}
		for i := top + 1; i <= bottom; i++ {
			ans = append(ans, matrix[i][right])
		}
		if left < right && top < bottom {
			for i := right - 1; i >= left; i-- {
				ans = append(ans, matrix[bottom][i])
			}
			for i := bottom - 1; i > top; i-- {
				ans = append(ans, matrix[i][left])
			}
		}
		top++
		bottom--
		left++
		right--
	}

	return ans
}
  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值