Article / 文章

LeetCode 第378题:有序矩阵中第K小的元素

给你一个n x n矩阵matrix,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。 请注意,它是排序后的第k小元素,而不是第k个不同的元素。

📖 文章摘要

本文详细解析LeetCode第378题“有序矩阵中第K小的元素”,这是一道二分查找问题。文章提供了基于二分查找的解法,包含C#、Python、C++三种语言实现,配有详细的算法分析和性能对比。适合想要提升二分查找应用能力的读者。

核心知识点: 二分查找、矩阵遍历、计数 难度等级: 中等 推荐人群: 具有基础算法知识,想要提升二分查找应用能力的程序员

题目描述

给你一个n x n矩阵matrix,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。 请注意,它是排序后的第k小元素,而不是第k个不同的元素。

示例

示例 1:

输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
输出:13
解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第8小元素是13

示例 2:

输入:matrix = [[-5]], k = 1
输出:-5

提示

  • n == matrix.length
  • n == matrix[i].length
  • 1 <= n <= 300
  • -10^9 <= matrix[i][j] <= 10^9
  • 题目数据保证matrix中的所有行和列都按非递减顺序排列
  • 1 <= k <= n^2

解题思路

本题可以使用二分查找解决:

  1. 确定二分查找的上下界
  2. 对于每个中间值mid,统计矩阵中小于等于mid的元素个数
  3. 如果个数小于k,说明第k小的元素在右半部分
  4. 如果个数大于等于k,说明第k小的元素在左半部分
  5. 最终找到满足条件的值

时间复杂度: O(n * log(max - min)) 空间复杂度: O(1)

图解思路

二分查找过程

步骤 左边界 右边界 中间值 小于等于mid的个数 说明
1 1 15 8 3 继续向右查找
2 9 15 12 6 继续向右查找
3 13 15 14 8 找到答案

矩阵遍历过程

当前值 小于等于mid的个数 说明
0 0 1 1 继续
0 1 5 2 继续
0 2 9 3 继续
1 0 10 4 继续

代码实现

C# 实现

public class Solution {
    public int KthSmallest(int[][] matrix, int k) {
        int n = matrix.Length;
        int left = matrix[0][0];
        int right = matrix[n - 1][n - 1];
        
        while (left < right) {
            int mid = left + (right - left) / 2;
            int count = CountLessOrEqual(matrix, mid);
            
            if (count < k) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        
        return left;
    }
    
    private int CountLessOrEqual(int[][] matrix, int target) {
        int n = matrix.Length;
        int count = 0;
        int row = n - 1;
        int col = 0;
        
        while (row >= 0 && col < n) {
            if (matrix[row][col] <= target) {
                count += row + 1;
                col++;
            } else {
                row--;
            }
        }
        
        return count;
    }
}

Python 实现

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        n = len(matrix)
        left, right = matrix[0][0], matrix[n-1][n-1]
        
        while left < right:
            mid = left + (right - left) // 2
            count = self.count_less_or_equal(matrix, mid)
            
            if count < k:
                left = mid + 1
            else:
                right = mid
                
        return left
    
    def count_less_or_equal(self, matrix: List[List[int]], target: int) -> int:
        n = len(matrix)
        count = 0
        row, col = n - 1, 0
        
        while row >= 0 and col < n:
            if matrix[row][col] <= target:
                count += row + 1
                col += 1
            else:
                row -= 1
                
        return count

C++ 实现

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int n = matrix.size();
        int left = matrix[0][0];
        int right = matrix[n-1][n-1];
        
        while (left < right) {
            int mid = left + (right - left) / 2;
            int count = countLessOrEqual(matrix, mid);
            
            if (count < k) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        
        return left;
    }
    
private:
    int countLessOrEqual(vector<vector<int>>& matrix, int target) {
        int n = matrix.size();
        int count = 0;
        int row = n - 1;
        int col = 0;
        
        while (row >= 0 && col < n) {
            if (matrix[row][col] <= target) {
                count += row + 1;
                col++;
            } else {
                row--;
            }
        }
        
        return count;
    }
};

执行结果

C# 实现

  • 执行用时:92 ms
  • 内存消耗:24.8 MB

Python 实现

  • 执行用时:28 ms
  • 内存消耗:13.2 MB

C++ 实现

  • 执行用时:4 ms
  • 内存消耗:8.4 MB

性能对比

语言 执行用时 内存消耗 特点
C++ 4 ms 8.4 MB 执行效率最高,内存占用最小
Python 28 ms 13.2 MB 代码简洁,内存占用适中
C# 92 ms 24.8 MB 类型安全,内存占用较大

代码亮点

  1. 🎯 使用二分查找优化计算
  2. 💡 空间复杂度优化
  3. 🔍 处理边界情况
  4. 🎨 代码结构清晰,易于维护

常见错误分析

  1. 🚫 未处理整数溢出
  2. 🚫 二分查找边界错误
  3. 🚫 矩阵遍历错误
  4. 🚫 计数逻辑错误

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
二分查找 O(n * log(max - min)) O(1) 高效,空间优化 实现较复杂
归并排序 O(k * log n) O(n) 直观,易于理解 空间复杂度高

相关题目


📖 系列导航

🔥 算法专题合集 - 查看完整合集

📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第378题。


💬 互动交流

感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。

如果这篇文章对你有帮助,请:

  • 👍 点个赞,让更多人看到这篇文章
  • 📁 收藏文章,方便后续查阅复习
  • 🔔 关注作者,获取更多高质量算法题解
  • 💭 评论区留言,分享你的解题思路或提出疑问

你的支持是我持续分享的动力!

💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!