[LeetCode 378] Kth elemento más pequeño en una matriz ordenada

Dada una   matriz n  x  n donde cada una de las filas y columnas están ordenadas en orden ascendente, encuentra el késimo elemento más pequeño en la matriz.

Tenga en cuenta que es el késimo elemento más pequeño en el orden ordenado, no el kth elemento distinto.

Ejemplo:

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

retorno 13.

 

Nota:
Puede suponer que k siempre es válido, 1 ≤ k ≤ n ^ 2.

 

La observación clave aquí es que hemos ordenado filas y columnas por separado. La matriz completa no está necesariamente ordenada de arriba a abajo, de izquierda a derecha. El ejemplo dado es engañoso a propósito. 

 

Solución 1. Montón mínimo, tiempo de ejecución de O (k * log n), espacio de O (n).

1. Agregue la primera fila a un montón mínimo con el valor, la fila y la información de la columna.

2. sondee el valor más pequeño del montón mínimo y luego agregue su siguiente valor en la misma columna. Repita esto k veces. Debido a que cada fila está ordenada y cada columna también está ordenada, se garantiza que siempre sondeamos el siguiente valor más pequeño en toda la matriz.

 

 

clase Solución {
     public  int kthSmallest ( int [] [] matrix, int k) {
         int m = matrix.length, n = matrix [0 ] .length; 
        PriorityQueue < int []> minPq = new PriorityQueue <> (Comparator.comparingInt (a -> a [0 ]));
        for ( int i = 0; i <n; i ++ ) { 
            minPq.add ( new  int [] {matrix [0] [i], 0 , i}); 
        } 
        
        int ans = 0 ;
        while (k> 0 ) {
             int[] curr = minPq.poll (); 
            ans = curr [0 ];
            if (curr [1] <matrix.length - 1 ) { 
                minPq.add ( new  int [] {matrix [curr [1] + 1] [curr [2]], curr [1] + 1, curr [2 ] }); 
            } 
            k - ; 
        } 
        return ans; 
    } 
}

 

Variación de la solución 1.

En la solución anterior, agregamos toda la primera fila al montón mínimo inicialmente. En su lugar, podemos elegir solo agregar matriz [0] [0] y luego, para cada elemento que se sondea desde el montón mínimo, intentamos agregar el número que está justo a su derecha y el número que está justo al final. Sin embargo, necesitaremos O (N ^ 2) contabilidad adicional para realizar un seguimiento si ya hemos agregado un número. 

 

Considere este ejemplo: cuando se sondea 3, intentamos agregar 5 y 7; cuando se sondea 6, intentamos agregar 7 y 11. ¡Si no hay seguimiento, se agregará 7 dos veces!

1 3 5

6 7 12

11 14 14

 

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        PriorityQueue<int[]> minPq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
        boolean[][] added = new boolean[matrix.length][matrix[0].length];
        minPq.add(new int[]{matrix[0][0], 0, 0});
        added[0][0] = true;
        int ans = 0;
        while(k > 0) {
            int[] curr = minPq.poll();
            ans = curr[0];
            if(curr[1] < matrix.length - 1 && !added[curr[1] + 1][curr[2]]) {
                minPq.add(new int[]{matrix[curr[1] + 1][curr[2]], curr[1] + 1, curr[2]});
                added[curr[1] + 1][curr[2]] = true;
            }
            if(curr[2] < matrix[0].length - 1 && !added[curr[1]][curr[2] + 1]) {
                minPq.add(new int[]{matrix[curr[1]][curr[2] + 1], curr[1], curr[2] + 1});
                added[curr[1]][curr[2] + 1] = true;
            }
            k--;
        }
        return ans;
    }
}

 

 

 

Solution 2. Binary Search on possible answer range, O(maxV * N) runtime, O(1) space.

 

Each time we check the middle value MID of the current search range: if there are < k numbers that are <= MID, search on [mid + 1, right]; else search on[left, mid].

 

The countSmallerAndEqual method takes O(N + N) which is O(N) runtime. This is because for matrix[i][j],  we have matrix[k][j] >= matrix[i][j], k > i; matrix[i][k] >= matrix[i][j], k > j.

So as we search for the total number of values that are <= MID, j can only decrease as i increases, we'll never reset j back to matrix[0].length - 1. Essentially, this count method just increases i from 0 to n - 1 and decreases j from n - 1 to 0.

 

 

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int l = matrix[0][0], r = matrix[matrix.length - 1][matrix[0].length - 1];
        
        while(l < r - 1) {
            int mid = l + (r - l) / 2;
            if(countSmallerAndEqual(matrix, mid) < k) {
                l = mid + 1;
            }
            else {
                r = mid;
            }
        }
        if(countSmallerAndEqual(matrix, l) >= k) {
            return l;
        }
        return r;
    }
    private int countSmallerAndEqual(int[][] matrix, int t) {
        int cnt = 0, j = matrix[0].length - 1;
        for(int i = 0; i < matrix.length; i++) {
            while(j >= 0 && matrix[i][j] > t) {
                j--;
            }
            cnt += j + 1;
        }
        return cnt;
    }
}

 

 

 

 

Related Problems

[LeetCode 287] Find the Duplicate Number

[LeetCode 373] Find K Pairs with Smallest Sums

[LeetCode 719] Find K-th Smallest Pair Distance

Supongo que te gusta

Origin www.cnblogs.com/lz87/p/7498510.html
Recomendado
Clasificación