Leetcode:NO.378 有序矩陣中第K小的元素 二分法

題目

給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第 k 小的元素。
請注意,它是排序後的第 k 小元素,而不是第 k 個不同的元素。

示例:

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

返回 13
提示:
你可以假設 k 的值永遠是有效的,1 ≤ k ≤ n2 。

鏈接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix

解題記錄

  • 通過數組的sort方法進行處理
  • 通過將二維矩陣變成一維數組
  • 然後排序後獲取第k-1位即爲所求
/**
 * @author ffzs
 * @describe
 * @date 2020/7/2
 */
public class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int[] res = new int[matrix.length * matrix.length];
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix.length; j++) {
                res[i*matrix.length + j] = matrix[j][i];
            }
        }
        Arrays.sort(res);
        return res[k-1];
    }
}

在這裏插入圖片描述

/**
 * @author ffzs
 * @describe
 * @date 2020/7/2
 */
public class Solution2 {
    public static int kthSmallest(int[][] matrix, int k) {
        int[] res = new int[matrix.length * matrix.length];
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix.length; j++) {
                res[i*matrix.length + j] = matrix[j][i];
            }
        }
        return quickSort(res, 0, res.length-1, res.length+1-k);
    }

    private static int quickSort(int[] lst, int l, int r, int k){
        if (l == r) return lst[l];
        int mid = lst[l+r >> 1];
        int left = l, right = r;
        while (true) {
            while (lst[left] < mid) left ++;
            while (lst[right] > mid) right --;
            if (left < right) swap(lst, left++, right--);
            else break;
        }
        if (r-right >= k) return quickSort(lst, right+1, r, k);
        else return quickSort(lst, l, right, k-(r-right));
    }

    private static void swap (int[] lst, int i, int j) {
        int tmp = lst[i];
        lst[i] = lst[j];
        lst[j] = tmp;
    }

    public static void main(String[] args) {
//        int[][] matrix = {{1,5,9}, {10,11,13}, {12,13,15}};
        int[][] matrix = {{1,2}, {1,3}};
        System.out.println(kthSmallest(matrix, 4));
    }
}

在這裏插入圖片描述

  • 本題用上面的方法求其實是有浪費步驟,因爲本題的數組是部分有序的,就是說我們想要求第K小數並不需要排序過程,只要通過二分法進行切割即可
/**
 * @author ffzs
 * @describe
 * @date 2020/7/2
 */
public class Solution3 {
    public int kthSmallest(int[][] matrix, int k) {
        int n = matrix.length;
        int left = matrix[0][0], right = matrix[n-1][n-1];
        while (left < right) {
            int mid = left+right >> 1;
            if (countLeft(matrix, mid) < k) left = mid +1;
            else right = mid;
        }
        return left;
    }

    private int countLeft (int[][] matrix, int mid) {
        int count = 0;
        for (int[] ints : matrix) {
            int j = 0;
            while (ints[j] <= mid) j++;
            count += j;
        }
        return count;
    }
}

在這裏插入圖片描述

  • 由於每列數據也是遞增的,那麼統計mid左邊個數的時候,可以繼承之前的列數,因爲下層該列的數一定不大於上層
    private int countLeft(int[][] matrix, int mid) {
        int count = 0;
        int j = 0;
        for (int i = matrix.length - 1; i >= 0; --i) {
            while (j < matrix.length && matrix[i][j] <= mid) j++;
            count += j;
        }
        return count;
    }

在這裏插入圖片描述

python一行解題

使用原生api

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        return sorted(__import__('functools').reduce(__import__('operator').add, matrix))[k-1]

在這裏插入圖片描述

使用numpy

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        return __import__("numpy").sort(__import__("numpy").ravel(matrix))[k-1]

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章