web-dev-qa-db-ja.com

ソートされた行列のK番目に小さい要素

これは面接の質問です。

Kを見つけるth 行と列がソートされた行列の最小要素。
Kが正しいですかth 最小の要素は、a[i, j]などのi + j = Kの1つですか?

20
Michael

誤り。

次のような単純な行列を考えてみましょう。

_1 3 5
2 4 6
7 8 9
_

9は最大(9番目に小さい)要素です。ただし、9はA [3、3]、および3 + 3!= 9にあります(どのインデックス規則を使用しても、それは真ではありません)。


最小要素を効率的に見つけるためにヒープを追加して行を段階的にマージすることにより、O(k log n)時間でこの問題を解決できます。

基本的に、最初の列の要素をヒープに入れ、それらが由来する行を追跡します。各ステップで、ヒープから最小要素を削除し、元の行から次の要素をプッシュします(行の終わりに達した場合は、何もプッシュしません)。最小値の削除と新しい要素の追加の両方で、コストO(log n)が発生します。 j番目のステップで、j番目に小さい要素を削除します。したがって、kステップの後、O(k log n)操作の総コスト(nは行数)が完了します。マトリックス内)。

上記のマトリックスの場合、最初はヒープ内の_1,2,7_から始めます。 _1_を削除し、_3_を追加して(最初の行が_1 3 5_であるため)、_2,3,7_を取得します。 _2_を削除し、_4_を追加して_3,4,7_を取得します。 _3_を削除し、_5_を追加して_4,5,7_を取得します。 _4_を削除し、_6_を追加して_5,6,7_を取得します。グローバルにソートされた順序で要素を削除していることに注意してください。このプロセスを続行すると、k回の反復後にk番目に小さい要素が生成されることがわかります。

(マトリックスに列よりも多くの行がある場合は、代わりに列を操作して実行時間を短縮します。)

35
nneonneo

O(k log(k))ソリューション。

  • ミンヒープを構築します。

  • ヒープに_(0,0)_を追加します。 kthの最小要素が見つかりませんでしたが、ヒープから一番上の要素_(x,y)_を削除し、次の2つの要素[(x+1,y)と_(x,y+1)]_がない場合は追加します。 t以前に訪問されました。

サイズO(k)のヒープでO(k)操作を実行しているため、複雑です。

23
user1987143

左上隅(0,0)からマトリックスのトラバースを開始し、バイナリヒープを使用して「フロンティア」(マトリックスの訪問した部分と残りの部分の間の境界)を格納します。

Javaでの実装:

private static class Cell implements Comparable<Cell> {

    private final int x;
    private final int y;
    private final int value;

    public Cell(int x, int y, int value) {
        this.x = x;
        this.y = y;
        this.value = value;
    }

    @Override
    public int compareTo(Cell that) {
        return this.value - that.value;
    }

}

private static int findMin(int[][] matrix, int k) {

    int min = matrix[0][0];

    PriorityQueue<Cell> frontier = new PriorityQueue<>();
    frontier.add(new Cell(0, 0, min));

    while (k > 1) {

        Cell poll = frontier.remove();

        if (poll.y + 1 < matrix[poll.x].length) frontier.add(new Cell(poll.x, poll.y + 1, matrix[poll.x][poll.y + 1]));
        if (poll.x + 1 < matrix.length) frontier.add(new Cell(poll.x + 1, poll.y, matrix[poll.x + 1][poll.y]));

        if (poll.value > min) {
            min = poll.value;
            k--;
        }

    }

    return min;

}
1
bedrin

これは機能を使用しているようです。すべての行が並べ替えられますが、列ごとに並べ替えられた機能は使用されません。

0
jeffery.yuan

行列のK番目に小さい要素:

問題は以下のように絞り込むことができます。

kが20の場合、k * k行列を取ります(答えは間違いなくあります)。

これで、行をペアで繰り返しマージして、並べ替えられた配列を作成し、k番目に小さい数を見つけることができます。

0

前述のように、最も簡単な方法はmin heapを作成することです。 PriorityQueueを使用したJavaの実装は次のとおりです。

private int kthSmallestUsingHeap(int[][] matrix, int k) {

    int n = matrix.length;

    // This is not necessary since this is the default Int comparator behavior
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    };

    // building a minHeap
    PriorityQueue<Integer> pq = new PriorityQueue<>(n*n, comparator);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            pq.add(matrix[i][j]);
        }
    }

    int ans = -1;
    // remove the min element k times
    for (int i = 0; i < k; i++) {
        ans = pq.poll();
    }

    return ans;
}
0
Yar