378. The K-th smallest element in an ordered matrix

378. The K-th smallest element in an ordered matrix

Give you an n x n matrix, in which the elements of each row and column are sorted in ascending order to find the k-smallest element in the matrix.

Note that it is the k-th smallest element after sorting, not the k-th different element.

Input: matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
 Output: 13
 Explanation: the elements in the matrix are [1,5,9,10,11,12,13,13,15],The 8th element is 13

Minimum heap

According to the properties given by the title, each row of the matrix is an ordered array. The problem is transformed from this n n No. in n ordered arrays k k k = large number

Firstly, the first column is constructed into a minimum heap, then the minimum value num in the heap is deleted in turn, and the remaining minimum value of the matrix is added. The remaining minimum value is the value that num shifts one grid to the right. The transformation of the minimum heap (blue value) is as follows:

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        n = len(matrix) #Note: the matrix in the title is n*n, so the length and width are n

        col = [(matrix[i][0], i ,0) for i in range(n)] #Take out the value of the first column
        # matrix[i][0] is the specific value, and the following (i,0) is the position in the record matrix, which is convenient for adding the next one each time you move right
        heapq.heapify(col) #Become a heap
        for i in range(k - 1): #Play a total of K times: k-1 times here and 1 time when you return
            num, x, y = heapq.heappop(col) #Eject the smallest one in the heap
            if y != n - 1: #If this line hasn't been played yet
                heapq.heappush(col , (matrix[x][y+1], x ,y+1 )) #Add a value to the right of num
        return heapq.heappop(col)[0]


dichotomy

  1. Find the smallest number in the two-dimensional matrix l e f t l e f t left, the largest number right, then k k k , a small number must be left ∼ \sim ∼ right
  2. mid = ( =( =(​​ left + + +​​ right ) / / 2 ) // 2 )//2​​; Find less than or equal to in two-dimensional matrix m i d m i d Number of elements in mid count
  3. If this count is less than k k k. Mingdi k k The number with small k is in the right half and does not contain mid ⁡ \operatorname{mid} mid, i.e l e f t = m i d + 1 , r i g h t = l e f t=m i d+1, r i g h t= left=mid+1,right= right, ensuring the second k k Where is the small number k l e f t ∼ r i g h t l e f t \sim right Between left ∼ right
  4. If this count >= k k k. Mingdi k k A small number of k is in the left half and may contain mid, i.e l e f t = l e f t , r i g h t = l e f t=l e f t, r i g h t= left=left,right= mid ⁡ \operatorname{mid} mid, the second k k Where is the small number k l e f t ∼ r i g h t l e f t \sim right Between left ∼ right
  5. Because the second cycle is guaranteed in each cycle k k Where is the small number k l e f t ∼ r i g h t l e f t \sim right Between left ∼ right, when l e f t = = r i g h t l e f t==r i g h t When left==right, the k k The small number of k is found to be equal to r i g h t \mathrm{right} right

Note: here l e f t , m i d , r i g h t left ,mid ,right left, mid and right are numeric values, not index positions.

The calculation of count is as follows: m i d = 8 mid =8 mid=8.

The walking method can be described as follows:

  • Initial position at m a t r i x [ n − 1 ] [ 0 ] matrix[n - 1][0] matrix[n − 1] [0] (i.e. lower left corner);
  • Set current position as matrix ⁡ [ i ] [ j ] \operatorname{matrix}[i][j] matrix[i][j] . if matrix ⁡ [ i ] [ j ] ≤ m i d \operatorname{matrix}[i][j] \leq m i d If matrix[i][j] ≤ mid, the current column will not be greater than m i d m i d Number of mid (i.e i + 1 i+1 i+1) accumulate in count and move to the right, otherwise move up;
  • Keep moving until you get out of the grid.
class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        row = len(matrix)
        col = len(matrix[0])
        left = matrix[0][0]
        right = matrix[row - 1][col - 1]
        while left < right:
            #Each cycle ensures that the number k smaller is between left and right. When left==right, the number k smaller is left
            mid = left+(right-left)//2
            count = self.findNotBiggerThanMid(matrix, mid, row, col)
            if count<k:
                #The number smaller than k is in the right half and does not contain mid
                left = mid + 1
            else :
                #The small number k is in the left half and may contain mid
                right = mid
        return right

    def findNotBiggerThanMid(self,matrix,mid,row,col):
        #Find the number of the last < = mid in each column, that is, know how many < = mid in each column
        i, j = row - 1, 0
        count =0
        while i >= 0 and j < col:
            if matrix[i][j] <= mid:
                count += i + 1
                j += 1
            else:
                i -= 1
        return count

reference resources

Krahets - LeetCode (LeetCode CN. Com)

Tags: Python Algorithm linear algebra

Posted on Fri, 19 Nov 2021 19:20:39 -0500 by apenster