前言
大家看每天一道leetcode的,帮忙投个票~
今天发起了leetcode刷题投票&粉丝福利活动,见我公众号今天的另一篇。11.1号打卡~
题目
leetcode378-有序矩阵中第K小的元素
英文链接:
https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/
中文链接:
https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/
分类:二分查找类
题目详述
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15] ], k = 8, 返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n2 。
暴力解决
思路
额,看到这个题目,一开始大体思路就是暴力解决;
遍历整个二维数组,然后把这个二维数组存到一个一维数组中,然后对这个一维数组,进行排序,然后取这个一维数组第k个值就行。
代码
1class Solution {
2 public int kthSmallest(int[][] matrix, int k) {
3 if(matrix.length == 0 || matrix[0].length == 0)
4 return -1;
5 int rows = matrix.length;
6 int cols = matrix[0].length;
7 int number = rows * cols;
8 int [] list = new int[number];
9 int count = 0;
10 for(int i=0;i<rows;i++)
11 {
12 for(int j=0;j<cols;j++)
13 {
14 list[count] = matrix[i][j];
15 count++;
16 }
17 }
18 Arrays.sort(list);
19 return list[k-1];
20 }
21}
二分解决
思路
由于是一个矩阵,左上角的数是最小值,右下角的数是最大值,所以可以利用这一个特点来进行二分,每次取两个边界的值进行除以2,得到一个mid值;
然后根据这个mid值,统计整个矩阵中,小于mid值的个数,如果小于mid的值的个数刚好大于等于k个,那么说明应该缩小right的值到mid,如果小于k个,那么说明left应该变成mid;
这样一步步进行紧逼,找到最后的这个数据。
代码
1class 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 + 1 < right) {
6 int mid = (right - left) / 2 + left;
7 int num = count(matrix, mid);
8 if (num >= k) {
9 right = mid;
10 } else {
11 left = mid;
12 }
13 }
14 if (count(matrix, right) <= k - 1) return right;
15 return left;
16 }
17 public int count(int[][] matrix, int target) {
18 int n = matrix.length;
19 int i = n - 1, j = 0;
20 int res = 0;
21 while (i >= 0 && j < n) {
22 if (matrix[i][j] < target) {
23 res += i + 1; //index + 1 = number of elements.
24 j++;
25 } else {
26 i--;
27 }
28 }
29 return res;
30 }
31}
代码讲解
17行到30行代码就是求矩阵中小于target的数的大小,这里的话从第0列开始的最底层开始找,如果左下角的数比target小,那么说明这一列的数都是小于target所以,也就是出现了代码22行到24行,因为这个一列已经找过了,所以j++,移动到下一列去找;
如果左下角的数比target大,由于每一行递增,所以只能是i--,来去找下一行;以上就是对17行-30行代码的讲解
题目中使用了二分查找,去找最小值和最大值的中间值,如果小于中间值的个数是k个或者大于k个,那么让right去等于mid,往左边逼近;
如果小于中间值mid的个数是小于k的,那么说明不够k个,也就只能取把left变大,等于mid;
然后循环结束的条件是left+1<right;说明这时候结束的时候已经是left与right无限逼近了,这个时候left与right的中间值在数组里面(这里我也没有数学证明,left与right一直求中间值,那么最后中间值mid一定在数组里面???这个我自己试验了几个数组,确实是这样子,但是我数学能力有限,无法去证明,有人能证明吗,欢迎评论区留言)
结束语
2018.11.1打卡~
END
推荐阅读
leetcode34-在排序数组中查找元素的第一个和最后一个位置
扫一扫

有3T编程资料等你来拿
548

被折叠的 条评论
为什么被折叠?



