|
| 1 | +""" |
| 2 | +Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. |
| 3 | +
|
| 4 | +Note that it is the kth smallest element in the sorted order, not the kth distinct element. |
| 5 | +
|
| 6 | +Example: |
| 7 | +
|
| 8 | +matrix = [ |
| 9 | + [ 1, 5, 9], |
| 10 | + [10, 11, 13], |
| 11 | + [12, 13, 15] |
| 12 | +], |
| 13 | +k = 8, |
| 14 | +
|
| 15 | +return 13. |
| 16 | +Note: |
| 17 | +You may assume k is always valid, 1 ≤ k ≤ n2. |
| 18 | +
|
| 19 | +
|
| 20 | +找到第k小个数。 |
| 21 | +
|
| 22 | +测试用例: |
| 23 | +https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/ |
| 24 | +
|
| 25 | +
|
| 26 | +思路是用了堆: |
| 27 | +Python 有内置的堆模块,需要进行研究自写。 2018/08/02待跟进。 |
| 28 | +
|
| 29 | +堆: |
| 30 | +堆是一个完全二叉树,完全二叉树是除了最底层,其他层都是铺满的。 |
| 31 | + 0 |
| 32 | +
|
| 33 | + 1 2 |
| 34 | +
|
| 35 | + 3 4 5 6 |
| 36 | +
|
| 37 | + 7 8 9 10 11 12 13 14 |
| 38 | +
|
| 39 | + 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
| 40 | +
|
| 41 | +堆又分为最大堆与最小堆,最小堆是根节点是整个堆中最小的,最大堆则是最大的。 |
| 42 | +
|
| 43 | +堆的操作分为:插入,取顶。 |
| 44 | +大部分情况下插入时的数据都是无序的,所以要保证最大堆与最小堆需要的操作肯定要有上浮与下沉。 |
| 45 | +上浮: |
| 46 | +最小堆中: |
| 47 | +如果父节点比自己大则自己上浮。 |
| 48 | +如果子节点比自己小则自己下沉。 |
| 49 | +也就是做数据交换,一直上浮或下沉到符合条件为止。 |
| 50 | +
|
| 51 | +代码待添加... |
| 52 | +
|
| 53 | +
|
| 54 | +""" |
| 55 | +''' |
| 56 | +内置heapq的第一个版本: |
| 57 | +运行时间长,但并未TLE.passed... |
| 58 | +
|
| 59 | +import heapq |
| 60 | +
|
| 61 | +class Solution(object): |
| 62 | + def kthSmallest(self, matrix, k): |
| 63 | + """ |
| 64 | + :type matrix: List[List[int]] |
| 65 | + :type k: int |
| 66 | + :rtype: int |
| 67 | + """ |
| 68 | + heap = [] |
| 69 | + |
| 70 | + for i in matrix: |
| 71 | + for j in i: |
| 72 | + heapq.heappush(heap, j) |
| 73 | + |
| 74 | + for i in range(k-1): |
| 75 | + heapq.heappop(heap) |
| 76 | + |
| 77 | + return heap[0] |
| 78 | +''' |
| 79 | + |
| 80 | +''' |
| 81 | +第二个版本: |
| 82 | +使用sorted. 每次都根据每个列表的0进行排序,然后取出。直到k=0. |
| 83 | +排序时间复杂度为平均为 O(log len(n))。需要进行k次,所以是 O(klog len(n))。 |
| 84 | +理想情况下应该是最快的,但在书写时sorted在数据量过大时都会重新生成数组,所以导致很慢。 |
| 85 | +改进版本是直接打散列表,然后一次性sorted,这样的时间复杂度为 O(nlogn),也很容易写,但不想这样。 |
| 86 | +
|
| 87 | +# 1 |
| 88 | +原以为会TTL,居然没有,跑了1778ms,也是最慢的。 |
| 89 | +
|
| 90 | +class Solution(object): |
| 91 | + def kthSmallest(self, matrix, k): |
| 92 | + """ |
| 93 | + :type matrix: List[List[int]] |
| 94 | + :type k: int |
| 95 | + :rtype: int |
| 96 | + """ |
| 97 | + |
| 98 | + while k: |
| 99 | + # matrix = sorted(matrix, key=lambda x: x[0]) |
| 100 | + matrix.sort(key=lambda x: x[0]) |
| 101 | + pop = matrix[0][0] |
| 102 | + matrix[0] = matrix[0][1:] |
| 103 | + if not matrix[0]: |
| 104 | + matrix = matrix[1:] |
| 105 | + k -= 1 |
| 106 | + |
| 107 | + return pop |
| 108 | +''' |
| 109 | +''' |
| 110 | +基于第二版的改进: |
| 111 | +第二版的性能瓶颈应该是在排序时会重新移动大量的元素,如果每次仅对len(n)个元素排序呢? |
| 112 | +每次都会for 一遍 len(n),生成一个新的 列表,列表中的元素是 ([0], index),然后排序这个列表。 |
| 113 | +也就是说不在排序原列表,而是排序一个新的列表。 |
| 114 | +根据index去修正原列表。 |
| 115 | +
|
| 116 | +这版本TTl.这样排序会导致时间复杂度为(k*len(n)*log len(n)) |
| 117 | +''' |
| 118 | +''' |
| 119 | +class Solution(object): |
| 120 | + def kthSmallest(self, matrix, k): |
| 121 | + """ |
| 122 | + :type matrix: List[List[int]] |
| 123 | + :type k: int |
| 124 | + :rtype: int |
| 125 | + """ |
| 126 | + length = len(matrix) |
| 127 | + while k: |
| 128 | + # matrix = sorted(matrix, key=lambda x: x[0]) |
| 129 | + # matrix.sort(key=lambda x: x[0]) |
| 130 | + |
| 131 | + # 测试用例是Python 2. |
| 132 | + newMatrix = sorted([(matrix[i][0], i)for i in xrange(length)], key=lambda x: x[0]) |
| 133 | +
|
| 134 | + pop = matrix[newMatrix[0][1]][0] |
| 135 | + matrix[0] = matrix[newMatrix[0][1]][1:] |
| 136 | + if not matrix[0]: |
| 137 | + matrix = matrix[1:] |
| 138 | + k -= 1 |
| 139 | + |
| 140 | + return pop |
| 141 | +''' |
| 142 | + |
| 143 | +''' |
| 144 | +第四版思路: |
| 145 | +基于第二版改进: |
| 146 | +第二版每次都只取一个,如果取多个呢? |
| 147 | +比如第一次做归并排序时, |
| 148 | +我是 [[1]+[2]]+[3]]+[4]]+[5]]+[6]] |
| 149 | +而实际上应该是 |
| 150 | +[[1]+[2]] + [[3]+[4]] + [[5]+[6]] |
| 151 | +[[1, 2, 3, 4]] + [[5, 6]]。 |
| 152 | +
|
| 153 | +如果每次排序后去除t个,需要保证 n[0][-1] < n[1][-1]。 |
| 154 | +比如 |
| 155 | +matrix = [ |
| 156 | + [ 1, 5, 9], |
| 157 | + [10, 11, 13], |
| 158 | + [12, 13, 15] |
| 159 | +], |
| 160 | +k = 8。 |
| 161 | +第二版中每次排序会去除一个最小的。 |
| 162 | +
|
| 163 | +matrix = [ |
| 164 | + [5, 9], |
| 165 | + [10, 11, 13], |
| 166 | + [12, 13, 15] |
| 167 | +], |
| 168 | +k = 7 |
| 169 | +
|
| 170 | +matrix = [ |
| 171 | + [9], |
| 172 | + [10, 11, 13], |
| 173 | + [12, 13, 15] |
| 174 | +], |
| 175 | +k = 6 |
| 176 | +
|
| 177 | +matrix = [ |
| 178 | + [10, 11, 13], |
| 179 | + [12, 13, 15] |
| 180 | +], |
| 181 | +k = 5 |
| 182 | +--- |
| 183 | +如果加入一条 |
| 184 | +matrix = [ |
| 185 | + [ 1, 5, 9], |
| 186 | + [10, 11, 13], |
| 187 | + [12, 13, 15] |
| 188 | +], |
| 189 | +k = 8 |
| 190 | +
|
| 191 | +# 进入此条的条件是 k > len(matrix[0]) |
| 192 | +
|
| 193 | +if matrix[0][-1] < matrix[1][0]: |
| 194 | + index1 = len(matrix[0]) |
| 195 | + # index2 = 0 |
| 196 | + # for t in xrange(matrix[1]): |
| 197 | + # if matrix[1][t] > matrix[0][-1]: |
| 198 | + # index2 = t |
| 199 | + # break |
| 200 | +
|
| 201 | +那么此时matrix[0] 将全部去除。k也相应的减去。 |
| 202 | +
|
| 203 | +还有一种情况是 0[-1] 并不小于 1[0] |
| 204 | +此时需要寻找 0 中小于 1[0]的数。 |
| 205 | +
|
| 206 | + for t in xrange(len(matrix[0])-1, -1, -1): |
| 207 | + if matrix[0][t] < matrix[1][0]: |
| 208 | + index1 = t |
| 209 | +那么此时将去除maxtrix[0][:t+1], k也减去相应的len. |
| 210 | +
|
| 211 | +< len 则退化为第二版。 |
| 212 | +
|
| 213 | +仍然TLE.... |
| 214 | +''' |
| 215 | +''' |
| 216 | +class Solution(object): |
| 217 | + def kthSmallest(self, matrix, k): |
| 218 | + """ |
| 219 | + :type matrix: List[List[int]] |
| 220 | + :type k: int |
| 221 | + :rtype: int |
| 222 | + """ |
| 223 | +
|
| 224 | + while k: |
| 225 | + matrix.sort(key=lambda x: x[0]) |
| 226 | + |
| 227 | + if k >= len(matrix[0]): |
| 228 | + if len(matrix) >= 2: |
| 229 | + if matrix[0][-1] <= matrix[1][0]: |
| 230 | + index1 = len(matrix[0]) |
| 231 | + else: |
| 232 | + for t in range(len(matrix[0])-1, -1, -1): |
| 233 | + if matrix[0][t] <= matrix[1][0]: |
| 234 | + index1 = t+1 |
| 235 | + break |
| 236 | + |
| 237 | + popedMatrix = matrix[0][:index1] |
| 238 | + matrix[0] = matrix[0][index1:] |
| 239 | + if not matrix[0]: |
| 240 | + matrix = matrix[1:] |
| 241 | + pop = popedMatrix[-1] |
| 242 | + k -= len(popedMatrix) |
| 243 | + # print(matrix, index1) |
| 244 | + else: |
| 245 | + return matrix[0][-1] |
| 246 | + else: |
| 247 | + pop = matrix[0][0] |
| 248 | + matrix[0] = matrix[0][1:] |
| 249 | + if not matrix[0]: |
| 250 | + matrix = matrix[1:] |
| 251 | + k -= 1 |
| 252 | + |
| 253 | + return pop |
| 254 | +''' |
| 255 | + |
| 256 | +''' |
| 257 | +目前为止,通过的是第一版和第二版,第三和第四基于2的改进都以失败告终。 |
| 258 | +第四版的性能瓶颈在于,如果1[0]一直小于0[-1] 那么就需要一直迭代,如果恰好每次0中只有[0]比1[0]小,那么就会迭代过多的次数。 |
| 259 | +从而导致 TLE. |
| 260 | +
|
| 261 | +''' |
0 commit comments