题目:
给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
你必须找到一个内存复杂度优于 O(n2) 的解决方案。
示例 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
- -109 <= matrix[i][j] <= 109
- 题目数据 保证 matrix 中的所有行和列都按 非递减顺序 排列
- 1 <= k <= n2
进阶:
- 你能否用一个恒定的内存(即 O(1) 内存复杂度)来解决这个问题?
- 你能在 O(n) 的时间复杂度下解决这个问题吗?这个方法对于面试来说可能太超前了,但是你会发现阅读这篇文章( this paper )很有趣。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
【二分查找】
根据题意得知二维矩阵从左向右依次递增,从上到小依次递增,故可得知, matrix[0][0]是最小值, matrix[n-1][n-1]是最大值。所需找的第k小的元素一定在最大值与最小值这个区间中, 现在将题目意思转换为在一个有序范围中查找值,可以考虑使用二分查找。
让 left = matrix[0][0],right = matrix[n-1][n-1],计算出mid的值,这样矩阵就会以mid为界限,分为两个部分。一部分元素是小于等于mid的部分,一部分是大于mid的部分。然后就需要判断第k小的元素到底在哪一个部分?(这样就可以明白,在较小的部分中至少应该有k个元素)
找比mid小的元素怎么找:
- 初始位置在 matrix[n - 1][0](即左下角);
- 设当前位置为 matrix[i][j],若 matrix[i][j] ≤ mid,则此元素及上方所有元素都是比mid 小的数,计算出这一列比mid小的元素累加到count中,并继续向右移动,否则,matrix[i][j] > mid,就需要向上移动才可能能找到比mid小的元素了;
- 不断移动直到走出格子为止。
比较count 与 k(二分查找):
- 循环条件:left < right, mid = left + (right - left) / 2;
- 如果count >= k,说明小元素部分的范围太大了(count==k时,表示刚好),则需要缩小 小元素的范围,即right = mid;
- 如果count < k,说明小元素部分的范围太小了,则需要扩大 小元素的范围,即left = mid + 1;
- 循环结束时:left == right,left或者right即为答案。
java代码:
1 class Solution { 2 public int kthSmallest(int[][] matrix, int k) { 3 int n = matrix.length; 4 int left = matrix[0][0], right = matrix[n - 1][n - 1]; 5 while(left < right){ 6 int mid = left + (right - left) / 2; 7 if (check(matrix, mid, k)){ 8 //true:count < k 9 left = mid + 1; 10 }else{ 11 //flase:count >= k 12 right = mid; 13 } 14 } 15 return left; 16 } 17 public boolean check(int[][] matrix, int mid, int k){ 18 int n = matrix.length; 19 int i = n-1, j = 0; 20 int count = 0; 21 while (i >= 0 && j < n){ 22 if (matrix[i][j] <= mid){ 23 //当前元素小于等于mid,则当前元素及改列上方的元素都小于mid 24 count += i + 1; 25 //继续向右移动 26 j += 1; 27 }else{ 28 //否则,向上查找小于mid的元素 29 i -= 1; 30 } 31 } 32 return count < k; 33 } 34 }
python3代码:
1 class Solution: 2 def kthSmallest(self, matrix: List[List[int]], k: int) -> int: 3 n = len(matrix) 4 def check(mid): 5 i, j, count = n-1, 0, 0 6 while i >= 0 and j < n: 7 if matrix[i][j] <= mid: 8 count += i + 1 9 j += 1 10 else: 11 i -= 1 12 return count < k 13 left, right = matrix[0][0], matrix[n-1][n-1] 14 while left < right: 15 mid = left + (right - left) // 2 16 if check(mid): 17 left = mid + 1 18 else: 19 right = mid 20 return left标签:right,java,matrix,python,元素,mid,力扣,int,left From: https://www.cnblogs.com/liu-myu/p/16954671.html