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
- 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
- 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
- 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
- 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
- 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