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 kth smallest element in the matrix.

Note that it is the kth smallest element in the sorted order, not the kth distinct element.

Example:

matrix = [
   [ 1,  5,  9],
   [10, 11, 13],
   [12, 13, 15]
],
k = 8,

return 13.

Note: 
You may assume k is always valid, 1 ≤ k ≤ n2.
思路1:klogk, 将最左上角的node加入priorityqueue,然后比这个点大的,只能是下面和右边,然后把这两个点加入,然后每次poll最小的,然后把接下来的点加入;

class Solution {
    class Node {
        public int x;
        public int y;
        public int value;
        public Node(int x, int y, int value) {
            this.x = x;
            this.y = y;
            this.value = value;
        }
    }
    
    public int kthSmallest(int[][] matrix, int k) {
        int count = 0;
        int n = matrix.length;
        boolean[][] visited = new boolean[n][n];
        PriorityQueue<Node> pq = new PriorityQueue<Node>((a, b) -> (a.value - b.value));
        pq.offer(new Node(0, 0, matrix[0][0]));
        visited[0][0] = true;
        
        int res = matrix[0][0];
        while(!pq.isEmpty() && count < k) {
            Node node = pq.poll();
            count++;
            if(count == k) {
                return node.value;
            }
            if(node.y + 1 < n && !visited[node.x][node.y + 1]) {
                pq.offer(new Node(node.x, node.y + 1, matrix[node.x][node.y + 1]));
                visited[node.x][node.y + 1] = true;
            }
            if(node.x + 1 < n && !visited[node.x + 1][node.y]) {
                pq.offer(new Node(node.x + 1, node.y, matrix[node.x + 1][node.y]));
                visited[node.x + 1][node.y] = true;
            }
        }
        return -1;
    }
}

思路2:二维数组中左上角的肯定是最小值,右下角的肯定是最大值,我们取他们的平均值,然后计算小于等于平均值的数字的个数,如果个数是小于k,那么说明要求的值是要大于平均值的,此时我们更新start的值;如果个数是大于k,那么说明要求的值就在start和mid之间,此时更新end的值。

中心思想是用start,end来逼近那个第k大的值,因为是整数,所以一直在用count来逼近,而不是找index坐标。注意count的时候,从左下角开始计算,如果matrix[x][y]比mid大,x上移,如果matrix[x][y]比mid小,count += x+1; O(nlgn)

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return -1;
        }
        int n = matrix.length;
        int start = matrix[0][0];
        int end = matrix[n - 1][n - 1];
        
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            if(count(matrix, mid) < k) {
                start = mid;
            } else {
                // count(matrix, mid) >= k;
                end = mid;
            }
        }
        
        if(count(matrix, start) < k) {
            return end;
        }
        return start;
    }
    
    // 算 <= target的个数;
    private int count(int[][] matrix, int target) {
        int n = matrix.length;
        int cnt = 0;
        int x = n - 1;
        int y = 0;
        while(0 <= x && x < n && 0 <= y && y < n) {
            if(target >= matrix[x][y]) {
                cnt += x + 1; // 注意x, y是index,所以是0 base的,算个数,要+1;
                y++;
            } else {
                // target < matrix[x][y];
                x--;
            }
        }
        return cnt;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值