Selection algorithms on sorted matrix

后端 未结 8 1749
野性不改
野性不改 2020-11-28 22:51

this is a google interview question :

Given a N*N Matrix. All rows are sorted, and all columns are sorted. Find the Kth Largest element of the matrix.

doing

相关标签:
8条回答
  • 2020-11-28 23:03

    rotate the matrix clockwise by 45 degrees. You will get a diamond shaped data set. The height will be 2N-1, number of elements in each row from top will be like: 1,2,3,4,5,4,3,2,1 for a N=5

    You will find out that each number in a row is always larger than any number above.

    for k-th row(counting from 1), you will have k elements for k < N and , 2N-k for k >= N k belongs to {1..2N-1}

    By computing accumulative number of elements from row 1 to k-1 and 1 to k, you will find the row where your target locates(sum(1 to k-1)

    Now that you have located a row of elements with worst case N total. You can sort them and then find the correct one. this taks O(N ln N)

    since N = sqrt(n), overall cost of this algorithm is O(sqrt(n) ln(sqrt(n)))

    0 讨论(0)
  • 2020-11-28 23:04

    You do a breath first search starting at the (0,0). (0,0)’s 2 children (0,1) & (1,0) are added to the potential candidates list for the 2nd element. Loop picking the smallest element in the potential candidates list to be the next element, add it’s children to the potential candidates list. Stop when find the kth element.

    Make the potential candidates list a min heap. The heap will never be bigger than n+m.

    Also you could do the reverse from the last element (n,m) if k is greater than n*m/2.

    Worst Case: this would be n*m/2 lg(n + m), instead of n*m lg(n * m) of sorting.

    0 讨论(0)
  • 2020-11-28 23:13

    You can find the kth smallest element in time O(n log n) expected, if you notice that:

    1. Generating a random number that lies between Array[i][j] and Array[k][l] such that Array[i][j] < Array[k][l] takes O(n) time (expected) and

    Using [1] as a subroutine, you can use a procedure similar to RANDOMIZED-SELECT to generate the kth smallest number in the whole array.

    0 讨论(0)
  • 2020-11-28 23:15

    The following is my C++ solution, which is based on a min heap. When a cell in the matrix is on the top of the min heap, the number at the right and/or the downside will be inserted into the heap.

    #include <vector>
    #include <algorithm>
    #include <functional>
    
    using namespace std;
    
    struct Entry {
        int value;
        int x;
        int y;
    
        bool operator < (const Entry& other) {
            return this->value > other.value;
        }
    };
    
    bool getKthNumber(int* matrix, int row, int col, int k, int* result){
        if(matrix == NULL || row <= 0 || col <= 0 || result == NULL)
            return false;
        if(k <= 0 || k > row * col)
            return false;
    
        vector<Entry> minHeap;
        Entry first = {matrix[0], 0, 0};
        minHeap.push_back(first);
        make_heap(minHeap.begin(), minHeap.end());
    
        for(int i = 0; i < k; ++i){
            first = minHeap[0];
            int x = first.x;
            int y = first.y;
            if(first.y == 0 && first.x < row - 1){
                Entry next = {matrix[(x + 1) * col], x + 1, y};
                minHeap.push_back(next);
                push_heap(minHeap.begin(), minHeap.end());
            }
            if(first.y < col - 1){
                Entry next = {matrix[x * col + y + 1], x, y + 1};
                minHeap.push_back(next);
                push_heap(minHeap.begin(), minHeap.end());
            }
    
            pop_heap(minHeap.begin(), minHeap.end());
            minHeap.pop_back();
        }
    
        *result = first.value;
        return true;
    }
    
    0 讨论(0)
  • 2020-11-28 23:20

    Based on N, you can find the diagonal where the element is located. For example in the matrix,

     1   5   7  12
     3   6   8  14
     4   9  10  15
    11  17  19  20
    

    You can deduce the diagonal by determining the total # of elements in the previous diagonals,

    /diagonal#/elements/# of elements/cumulative # of elements/
    /d1/ 1         / 1 / 1 /
    /d2/ 3 5       / 2 / 1+2 = 3 /
    /d3/ 4 6 7     / 3 / 1+2+3 = 6 /
    /d4/ 11 9 8 12 / 4 / 1+2+3+4 = 10 /
    /d5/ 17 10 14  / 3 /
    /d6/ 19 15     / 2 /
    /d7/ 20        / 1 /
    

    The reason why we need to find the diagonal is because the diagonals above will always have elements lesser than any of the current diagonal elements and the diagonals below will always have elements greater than any of the current diagonal elements.

    So, you can be sure that diagonal d4 has the required element(Since it contains 7th largest to 10th largest). Since until the previous diagonal there were 6 elements, you just need to find the 4th largest element in diagonal d4.

    0 讨论(0)
  • 2020-11-28 23:21

    With the matrix given in the example: If you want to search for the 7-th element, you know the 7-th element is in the elements M[4][1..4], M[1..4][4]. You obtain two arrays already sorted, 12,14,15,20 and 11,17,19 which can be merged. Then you apply a binary search which is O(log N).

    Generalize: for k-th biggest element in this matrix, you have to select the proper layer: [2N-1] + [2(N-1)-1]+...>=k so the algorithm to select the proper layer to lookout for is Sum[2(N-i)-1]>=k, for i=0,N-1, where i is the layer's number. After you find i, the layer number, you will have 2(N-i)-1 elements in that array that have to be merged and then searched. The complexity to search that layer is O(log[2(N-i)-1] = O(log(N-i))...

    The arithmetic progression leads to

    0>=i^2-2*N*i+k

    i1,2=N+-sqrt(N^2-k), where k is the element we search...

    0 讨论(0)
提交回复
热议问题