行と列のそれぞれが昇順で並べ替えられているn x n行列が与えられた 場合、行列のk番目に小さい要素を見つけます。
これは、ソートされた順序でk番目に小さい要素であり、k番目の個別の要素ではないことに注意してください。
例:
行列= [
[1、5、9]、
[10、11、13]、
[12、13、15]
]、
k = 8
戻る13。
注:
kは常に有効、1≤k≤n ^ 2と想定できます。
ここでの重要な観察は、行と列を別々にソートしたことです。マトリックス全体が上から下、左から右にソートされる必要はありません。与えられた例は意図的に誤解を招くものです。
解決策1.最小ヒープ、O(k * log n)ランタイム、O(n)スペース。
1.最初の行を、値、行、列情報を含む最小ヒープに追加します。
2.最小ヒープから最小値をポーリングし、同じ列に次の値を追加します。これをk回繰り返します。各行がソートされ、各列もソートされるため、マトリックス全体で次に小さい値を常にポーリングすることが保証されます。
クラスSolution { 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 - ; } ansを返します。 } }
ソリューションのバリエーション1。
上記のソリューションでは、最初の行全体を最初に最小ヒープに追加します。代わりに、matrix [0] [0]のみを追加することを選択できます。次に、最小ヒープからポーリングされる各要素について、その右側にある数とその一番下にある数を追加しようとします。ただし、すでに番号を追加した場合は、追跡するためにO(N ^ 2)の追加のブックキーピングが必要です。
次の例を検討してください。3がポーリングされると、5と7を追加しようとします。6がポーリングされると、7と11を追加しようとします。追跡がない場合、7が2回追加されます。
1 3 5
6 7 12
11 14 14
クラスSolution { public int kthSmallest(int [] [] matrix、int k){ PriorityQueue < int []> minPq = new PriorityQueue <>(Comparator.comparingInt(a- > a [0 ])); ブール値 [] []追加= 新しい ブール値 [matrix.length] [matrix [0 ] .length]; minPq.add(new int [] {matrix [0] [0]、0、0 }); 追加[ 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 ]}); 追加[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 }); 追加[curr [ 1]] [curr [2] + 1] = true ; } K - ; } ansを返します。 } }
ソリューション2.可能な回答範囲のバイナリ検索、O(maxV * N)ランタイム、O(1)スペース。
現在の検索範囲の中央値MIDをチェックするたびに、<= MIDである<k個の数値がある場合、[mid + 1、right]で検索します。それ以外の場合は[左、中]で検索します。
countSmallerAndEqualメソッドは、O(N)ランタイムであるO(N + N)を取ります。これは、matrix [i] [j]の場合、matrix [k] [j]> = matrix [i] [j]、k> i;となるためです。matrix [i] [k]> = matrix [i] [j]、k> j。
したがって、MID未満の値の総数を検索する場合、jはiが増加した場合にのみ減少する可能性があるため、jをmatrix [0] .length-1にリセットすることは決してありません。 0からn-1に、jをn-1から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