Skip to content

Commit 73ecbb6

Browse files
author
weiy
committed
kth smallest element in a sorted matrix/heap
1 parent 9f34e05 commit 73ecbb6

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed
+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
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

Comments
 (0)