0X00 leetcode 刷题
- LeetCode 378. Kth Smallest Element in a Sorted Matrix
- LeetCode 668. Kth Smallest Number in Multiplication Table
- LeetCode 786. K-th Smallest Prime Fraction
- LeetCode 719. Find K-th Smallest Pair Distance
0X01 基本模板总结
首先我们有这么一个基本问题
给定一个升序的数组:
[1, 5, 9, 10, 10, 20]
给定最小值 1 最大值 20 求 第 k 小的元素
hebing
对于第 kth 小的问题,有一种通用解法就是用 k size 的「最大堆」,这个以后再说,今天我们主要用二分查找
二分查找有一个模板:
lo, hi = min, max
while lo < hi:
mid = lo + (hi - lo) // 2
if check(xx):
r = m
else:
l = m + 1
return l
对于这个问题我们的解法如下:
class Solution:
def kth(self, nums, minNumber, maxNumber, k):
l, r = minNumber, maxNumber
# 返回比 n 小于等于的个数
def helper(start, end, nums, n):
if start == end:
return 1 if n > nums[start] else 0
if end - start == 1:
if n >= nums[end]: return 2
if n >= nums[start]: return 1
return 0
if n > nums[end]:
return end - start + 1
mid = start + (end - start) // 2
return helper(start, mid, nums, n) + helper(mid+1, end, nums, n)
return start
while l < r:
m = l + (r - l) // 2
if helper(m) >= k:
r = m
else:
l = m + 1
return l
a = [1, 4, 5, 5, 5, 5, 5, 5, 8]
s = Solution()
print(s.kth(a, 1, 8, 4))
对于这一种解法,一直有一个这么样的疑问
为什么二分搜索出来的值,一定在数组里面..
一定存在第 k 小的值,而且是唯一的
一定是 r 先找到最后的答案
r 找到答案后就不会改变了, 直到 l 与 r 合并
0X02 leetcode 做题
378. Kth Smallest Element in a Sorted Matrix
不是最优解..但是就是按照上面的模板改的...
如果有重复元素的话,我就还是用递归吧.迭代太复杂了
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
lo, hi = matrix[0][0], matrix[-1][-1]
def helper(start, end, nums, n):
if start == end:
return 1 if n >= nums[start] else 0
if end - start == 1:
if n >= nums[end]: return 2
if n >= nums[start]: return 1
return 0
if n >= nums[end]:
return end - start + 1
mid = start + (end - start) // 2
return helper(start, mid, nums, n) + helper(mid+1, end, nums, n)
while lo < hi:
mid = lo + (hi - lo) // 2
s = 0
for row in matrix:
s += helper(0, len(row) - 1, row, mid)
if s >= k:
hi = mid
else:
lo = mid + 1
return lo
668. Kth Smallest Number in Multiplication Table
class Solution:
def findKthNumber(self, m: int, n: int, k: int) -> int:
# 返回有多少个 <= x 的数
def helper(m, n, k, x):
count = 0
# 只需要把每一行的 x // i 加起来就行了
# 如果 i 大于 x x // i == 0 也就不需要继续算下去了
# 如果 m < x 那么剩下的也不用算了
# 所以最大值是 min(x, m)
for i in range(1, min(m+1, x+1)):
# 一行长度可能不够
count += min(x // i, n)
# 剪枝
if count >= k: return count
return count
l, r = 1, m * n + 1
while l < r:
mid = l + (r - l) // 2
if helper(m,n, k, mid) >= k:
r = mid
else:
l = mid + 1
return l
这道题用了模板题的结论,
在有重复的升序列数组中找到
下面两道题待做