面试刷题:矩阵对角线排序 Q1329

BG84

Posted by Blue Geek on April 10, 2020

面试刷题:矩阵对角线排序

By 青衣极客 Blue Geek In 2020-04-10

排序作为一种基本算法,已经不太可能直接作为面试题,但是 以排序作为基础内核来解决问题仍然是一个不错的出题点。Leetcode Q1329 就是一个很好的例子,难度并不大,却可以很好地检查开发者运用基础的排序算法解决问题的能力。这远比手动写一个大顶堆或者红黑树有意义得多,毕竟真实工作中大家不太可能这样做。

1. 题目 Q1329 矩阵对角线排序

给定一个 $m \times n$ 整数矩阵,按从左上角到右下角的 升序对角 对其进行排序,然后返回排序后的数组。

约束条件:

(a) m == mat.length
(b) n == mat[i].length
(c) 1 <= m, n <= 100
(d) 1 <= mat[i][j] <= 100

示例1

Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]
Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]

解释:

2. 解题思路

题意已经描述地很清楚了,就是每个对角线单独进行升序的排序。不过我们需要知道一点,即矩阵并不一定就是方阵。我们可以 逐个取出对角线元素,然后针对这些元素使用快速排序算法按升序排列,最后再将排序完成的元素回填到矩阵之中的对应位置处

对角线排序示意图

按照这个思路,排序已经不是难点了,真正的难点变成了按照对角线取元素和回填元素。从实现的角度来看,对左上角的对角线和右下角的对角线提取元素的方式还稍有差别,因此需要分开处理

左上和右下对角线分开处理

3. C++解决方案

按照以上的思路,这里给出C++的解决方案。

class Solution {
public:
    // Runtime: 28 ms, faster than 88.50%
    // Memory Usage: 10.6 MB, less than 100.00%
    vector<vector<int>> diagonalSort(vector<vector<int>>& mat) {
        int m = mat.size();
        int n = mat[0].size();
        vector<int> buff;  // avoid creating object repeatedly
        int r = 0, c = 0;
        // sort right-up
        for (int i=0; i<n; ++i) {
            buff.clear();
            r = 0, c = i;
            while(r < m && c < n) {
                buff.push_back(mat[r++][c++]);
            }
            // sort diag
            sort(buff.begin(), buff.end());
            // fill into mat
            r = 0, c = i;
            for (auto & v : buff) {
                mat[r++][c++] = v;
            }
        }
        // sort left-bottom
        for (int i=1; i<m; ++i) {
            buff.clear();
            r = i, c = 0;
            while (r < m && c < n) {
                buff.push_back(mat[r++][c++]);
            }
            // sort diag
            sort(buff.begin(), buff.end());
            // fill into mat
            r = i, c = 0;
            for (auto & v : buff) {
                mat[r++][c++] = v;
            }
        }
        return mat;
    }
};

在实现上需要说明的是,尽量减少零时变量的创建次数,尽量预先使用reserve()函数为vector分配内存。对于“前++”和“后++”这两种语法的使用可以使代码更简洁,如果解决可读性下降,也可以拆分开编写。

题外:

本频道创建了一个代码库专门用于管理和自动化测试Leetcode刷题代码,如果需要更方便地获取源码或者贡献解决方案,可以查看仓库:leetcode

【青衣极客】公众号



COMMENT

博客评论区功能由Github Issue提供,提交Issue时请以本文标题为话题

"BG84-面试刷题:矩阵对角线排序 Q1329"