类似的题目有:

373. Find K Pairs with Smallest Sums
378. Kth Smallest Element in a Sorted Matrix
668. Kth Smallest Number in Multiplication Table
719. Find K-th Smallest Pair Distance
786. K-th Smallest Prime Fraction

所有的问题都可以转化成找第k最小元素的问题

LeetCode 378

Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element.

1 暴力法(基于排序的方法)

将矩阵转成单维列表,进行排序,结果就是第k-1个元素

class Solution:def kthSmallest(self, matrix: List[List[int]], k: int) -> int:nums = [matrix[i][j] for i in range(len(matrix)) for j in range(len(matrix[0]))]nums = sorted(nums)return nums[k-1]

时间复杂度O(n^2 + n^2log(n^2)) = O(n^2 * log(n^2))

空间复杂度O(n^2)

2 基于优先队列的方法(部分排序)

不需要对整个数组进行排序,我们只需要找到第k个最小的元素。所以只需要建立一个大小为k的优先队列(或者用堆),结果就是堆中最大的那个值。

class Solution:def kthSmallest(self, matrix: List[List[int]], k: int) -> int:nums = []for i in range(len(matrix)):for j in range(len(matrix[0])):# 没有必要比较可以利用堆去pop掉最大的值达到比较的目的# if len(nums) == k:#     heapq.heappush(nums, - min(matrix[i][j], -heapq.heappop(nums)))# else:#     heapq.heappush(nums, - matrix[i][j])heapq.heappush(nums, - matrix[i][j])if len(nums) > k:heapq.heappop(nums)return -heapq.heappop(nums)

时间复杂度O(n^2 * log(k)) 循环 n^2次,每次循环中堆的push和pop时间复杂度都O(log(k)), 最坏的情况k = n^2退化成第一种方法

空间复杂度O(k)

3 基于优先队列的优化

以上两种方法都没有考虑矩阵本身的有序性,如果考虑矩阵本身的有序性则不需要对所有元素进行比较,因为有序性已经告诉了下一个最小值可能存在的位置。因为第一个最小值是在第一列第一行,所以可以把第一列的元素设置为初始值,每次移除一个最小值后补充该行的下一列元素即可。再去掉k-1个最小值后,第k个最小值就是pool中的最小值。

java版本

public int kthSmallest(int[][] matrix, int k) {PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {public int compare(int[] a, int[] b) { // (a[0], a[1]) and (b[0], b[1]) are positions in the matrixreturn Integer.compare(matrix[a[0]][a[1]], matrix[b[0]][b[1]]);}});int n = matrix.length;for (int i = 0; i < n; i++) {pq.offer(new int[] {i, 0});  // initialize the pool with elements from the first column}while (--k > 0) {                // remove the smallest elements from the matrix (k-1) timesint[] p = pq.poll();if (++p[1] < n) {pq.offer(p);             // add the next element in the same row if it exists}}return matrix[pq.peek()[0]][pq.peek()[1]];
}

python版本

class Solution:def kthSmallest(self, matrix: List[List[int]], k: int) -> int:col = len(matrix[0])row = len(matrix)nums = []# initialize with first col since the smallest must be in first column# python的堆比较的是第一个元素,所以把matrix的值放在第一位,第二第三位用来保存位置信息(row,col)for i in range(len(matrix)):tmp = [matrix[i][0], i, 0]heapq.heappush(nums, tmp)# remove k - 1 smallest ele, so that the result is the smallest one among the heap# 终止条件是 k = 1while k > 1:mini = heapq.heappop(nums)if mini[2] < col - 1:i = mini[1]j = mini[2]tmp = [matrix[i][j + 1], i, j + 1]heapq.heappush(nums, tmp)k -= 1return heapq.heappop(nums)[0]

时间复杂度:O(max(col, k) * log(col))  如果col大于k,时间复杂度由初始化的部分决定,否则由remove最小值的部分决定。

空间复杂度:O(row)

2,3两种方法的精髓就是用堆替代了比较的过程。将n变成了logn。

4 二分搜索法

某位大佬总结说二分搜索法是特殊的"trial and error" algorithm(试错法),简单的说就是随便找个可能的值(The candidate solution,The search space是The candidate solution的集合)试试,通过结果可以缩小搜索范围(The search space)。这种方法要求可以轻易的判断是否缩小范围(The verification algorithm

The candidate solution: in this case, the cadidate solution is simply an integer.

The search space: in this case, the search space is given by [MIN, MAX], where MIN and MAX are the minimum and maximum elements in the matrix, respectively.

The traverse method: in this case, we can do a binary search since the search space is sorted naturally in ascending order (this also accounts for the name "BinarySearch-based solution").

The verification algorithm: in this case, the verification algorithm is implemented by comparing the count of elements in the matrix less than or equal to the candidate solution, denoted as cnt, with the rank k: if cnt < k, we throw away the left half of the search space; otherwise we discard the right half.

class Solution:def kthSmallest(self, matrix: List[List[int]], k: int) -> int:col = len(matrix[0])row = len(matrix)# search space [l, r]l = matrix[0][0]r = matrix[row - 1][col - 1]while l < r:m = l + (r - l)//2# count the number which is less than midcnt = 0for i in range(row):j = col -1while j >= 0 and matrix[i][j] > m:j -= 1cnt += (j + 1)# binary search discard halfif cnt < k:# mid 是靠左的,可以取到l,所以l = mid + 1l = m + 1else:r = mreturn l

时间复杂度:O(row *col * log(row))   log(row)层循环,每层循环count number是linear的col * row。

空间复杂度:O(1)

5 Zigzag Search

同样是一种"trial and error" algorithm,与二分不同的是,search space不是[Min, Max]的连续取值,而是实际存在于输入矩阵的中值,所以这里不能用二分,只能沿着特定的方向一个一个遍历(从右上角或者左下角开始)。

The candidate solution: 输入矩阵中的值

The search space: 输入矩阵本身,不再是[Min, Max]

The traverse method: 由The verification algorithm决定要移动的方向(这里从右上角开始)

The verification algorithm: 通过分别比较 cnt_lt,cnt_le和k大小关系: 如果 cnt_le < k, 移动到下一行; else if cnt_lt >= k, 移动到前一列,否则等于k返回结果. 这里cnt_lt代表小于可能解的元素个数, 而cnt_le代表小于等于可能解的元素个数 (考虑可能存在重复值).

public int kthSmallest(int[][] matrix, int k) {int n = matrix.length;int row = 0;          // we start from the upper-right cornerint col = n - 1;      for (int cnt_le = 0, cnt_lt = 0; true; cnt_le = 0, cnt_lt = 0) {for (int i = 0, j = n - 1, p = n - 1; i < n; i++) {while (j >= 0 && matrix[i][j] > matrix[row][col]) j--;    // pointer j for counting cnt_lecnt_le += (j + 1);while (p >= 0 && matrix[i][p] >= matrix[row][col]) p--;   // pointer p for counting cnt_ltcnt_lt += (p + 1);}if (cnt_le < k) {         // candidate solution too small so increase itrow++; } else if (cnt_lt >= k) { // candidate solution too large so decrease itcol--;} else {                  // candidate solution equal to the kth smallest element so returnreturn matrix[row][col];}}
}

时间复杂度:O(row * row * col )  最多循环 2row 每层循环count number的时间复杂度是row * col

空间复杂度:O(1)

 Biselect

解决这类问题最快的算法,时间复杂度和空间复杂度都是线性的。了解一下即可。

https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/85201/c-on-time-on-space-solution-with-detail-intuitive-explanation

https://leetcode.com/problems/k-th-smallest-prime-fraction/discuss/115819/Summary-of-solutions-for-problems-%22reducible%22-to-LeetCode-378

有时间在研究。

7 如何把其他问题转化为这一类问题?

关键就是要构造一个row和col都是上升的矩阵:

  1. 加: matrix[i][j] = a[i'] + b[j']
  2. 减: matrix[i][j] = a[i'] - b[j']
  3. 乘: matrix[i][j] = a[i'] * b[j']
  4. 除: matrix[i][j] = a[i'] / b[j']

这里的a,b都是输入数组,而i' -> i和 j' -> j的映射关系不一定是相等的,只要可以满足双射就可以了。

比如Find K-th Smallest Pair Distance  https://blog.csdn.net/weixin_38087754/article/details/95218322这里的a和b都是同一个nums,而这里距离矩阵就是通过减法: matrix[i][j] = nums[i] - nums[j]构建的再用二分的方法去解决,在这道题中,i必须要大于j所以这里的矩阵只是半角矩阵。

Ref: https://leetcode.com/problems/k-th-smallest-prime-fraction/discuss/115819/Summary-of-solutions-for-problems-%22reducible%22-to-LeetCode-378

Kth Smallest Element in a Sorted Matrix相关推荐

  1. leetcode378. Kth Smallest Element in a Sorted Matrix

    题目要求 Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the ...

  2. 378. Kth Smallest Element in a Sorted Matrix

    文章目录 1题目理解 2 思路分析 2.1二分思路 2.2计算小于等于middle值的个数 3 拓展解决leetcode 668 1题目理解 输入:一个nxn的矩阵,每一行从左到右按照升序排列,每一列 ...

  3. 378. Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素

    Title 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素. 请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素. 示例: matrix = [ [ ...

  4. leetcode 378. Kth Smallest Element in a Sorted Matrix

    二分的方法解决 class Solution { public:int kthSmallest(vector<vector<int>>& matrix, int k) ...

  5. leetcode 378. Kth Smallest Element in a Sorted Matrix | 378. 有序矩阵中第 K 小的元素(小根堆)

    题目 https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/ 题解 套了下小根堆模板. class Solutio ...

  6. 利用二分法解决 leetcode 378. Kth Smallest Element in a Sorted Matrix

    问题简述 给定一个 n×nn \times n 的矩阵,矩阵中每行和每列的元素都按升序排列.给定一个 k(k∈[1,n2])k (k \in [1, n^2]), 求再整个矩阵中按从小到大排序为 kk ...

  7. leetcode378 Kth Smallest Element in a Sorted Matrix

    思路1: 使用堆. 实现: 1 class Solution 2 { 3 public: 4 int kthSmallest(vector<vector<int>>& ...

  8. LeetCode 230. Kth Smallest Element in a BST--C++,Python解法--面试真题--找二叉树中第K小的元素

    题目地址:Kth Smallest Element in a BST - LeetCode Given a binary search tree, write a function kthSmalle ...

  9. [LeetCode] Kth Smallest Element in a BST

    Kth Smallest Element in a BST Given a binary search tree, write a function kthSmallest to find the k ...

最新文章

  1. 【每日DP】day3 P1387 最大正方形(奇怪的DP增加了 / 二维前缀和)难度⭐⭐★
  2. 【PHPWord】插入Excel对象
  3. 数据结构源码笔记(C语言):哈希表的相关运算算法
  4. [AHOI2014/JSOI2014]支线剧情
  5. Oracle char 查询问题
  6. mybatis 中 foreach collection的三种用法
  7. TFS命令tf:undo(强制签入签出文件)
  8. python吧_python初始与安装 - Python东
  9. OpenShift ocp packages
  10. 卸载loadrunner
  11. Proxmox VE中出现TASK ERROR: command ‘apt-get update‘ failed: exit code 100的解决方法
  12. 百度鹰眼ajax 坐标转换,Web服务更新日志
  13. msdia80.dll是什么文件?msdia80.dll文件缺失怎么修复?
  14. 拟物设计和Angular的实现 - Material Design (持续更新)
  15. Steam如何打开控制台
  16. 针对ABCmouse的Xadmin管理端使用探究手册
  17. 软件测试精华总结,入门到精通全流程(必看,知识点很全)
  18. 树莓派的一生:树莓派十年
  19. 使用TLC2543来读取电压
  20. 程序员“薪资被应届生倒挂“现象明显,跳槽还是等待?

热门文章

  1. 国内一家数据中心提供商计划在美国纳斯达克上市
  2. [附源码]Python计算机毕业设计Django的酒店预订系统设计与实现
  3. Linux学习之ROS-Academy-for-Beginners安装记录与问题
  4. Java端飞书接口开发
  5. 易基因:DNA甲基化研究的3大前期探索性实验思路|干货系列
  6. cd ..和cd -
  7. 初中英语知识水平测试软件,初中英语学科知识与能力模拟测试九
  8. 6-8 从shape类派生出一个正n边形分数 10
  9. 2021 技术展望 | AV1 在 RTC 应用实践中的现状与展望
  10. 课设-机器学习课设-实现新闻分类