leetcode刷题记录——堆

215 数组中的第K个最大元素 Medium

给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

1
2
输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

1
2
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

思路

毫无思路可言,sorted直接搞定

代码

1
2
3
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
return sorted(nums, reverse=True)[k-1]

还有一个我之前写的版本,也顺便发一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def quick_select(nums, k):
pivot = random.choice(nums)
big, equal, small = [], [], []
for num in nums:
if num > pivot:
big.append(num)
elif num < pivot:
small.append(num)
else:
equal.append(num)
if k <= len(big):
return quick_select(big, k)
if len(nums) - len(small) < k:
return quick_select(small, k - len(nums) + len(small))
return pivot
return quick_select(nums, k)

时间复杂度

时间复杂度O(n log n),空间复杂度O(n),执行时间128ms,消耗内存27.3MB

502 IPO Hard

假设 力扣(LeetCode)即将开始 IPO 。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后得到最大总资本的方式。

给你 n 个项目。对于每个项目 i ,它都有一个纯利润 profits[i] ,和启动该项目需要的最小资本 capital[i]

最初,你的资本为 w 。当你完成一个项目时,你将获得纯利润,且利润将被添加到你的总资本中。

总而言之,从给定项目中选择 最多 k 个不同项目的列表,以 最大化最终资本 ,并输出最终可获得的最多资本。

答案保证在 32 位有符号整数范围内。

示例 1:

1
2
3
4
5
6
7
8
输入:k = 2, w = 0, profits = [1,2,3], capital = [0,1,1]
输出:4
解释:
由于你的初始资本为 0,你仅可以从 0 号项目开始。
在完成后,你将获得 1 的利润,你的总资本将变为 1。
此时你可以选择开始 1 号或 2 号项目。
由于你最多可以选择两个项目,所以你需要完成 2 号项目以获得最大的资本。
因此,输出最后最大化的资本,为 0 + 1 + 3 = 4。

示例 2:

1
2
输入:k = 3, w = 0, profits = [1,2,3], capital = [0,1,2]
输出:6

提示:

  • 1 <= k <= 105
  • 0 <= w <= 109
  • n == profits.length
  • n == capital.length
  • 1 <= n <= 105
  • 0 <= profits[i] <= 104
  • 0 <= capital[i] <= 109

思路

  1. 排序后方便进行,可以直接考虑当前资金
  2. 用最大堆来维护利润,堆顶元素就是当前能够启动的里面利润最大的
  3. 选择项目,每次迭代后将能够启动的项目加入最大堆并选择最大利润的启动

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
def findMaximizedCapital(self, k: int, W: int, Profits: List[int], Capital: List[int]) -> int:
n = len(Profits)
projects = sorted(zip(Capital, Profits))
max_heap = []
idx = 0

for _ in range(k):
while idx < n and projects[idx][0] <= W:
heapq.heappush(max_heap, -projects[idx][1])
idx += 1
if max_heap:
W -= heapq.heappop(max_heap)
else:
break
return W

时间复杂度

时间复杂度O(n log n),空间复杂度O(n),执行时间380ms,消耗内存40.4MB

373 查找和最小的 K 对数字 Medium

给定两个以 非递减顺序排列 的整数数组 nums1nums2 , 以及一个整数 k

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2

请找到和最小的 k 个数对 (u1,v1), (u2,v2)(uk,vk)

示例 1:

1
2
3
4
输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

示例 2:

1
2
3
4
输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
[1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

提示:

  • 1 <= nums1.length, nums2.length <= 105
  • -109 <= nums1[i], nums2[i] <= 109
  • nums1nums2 均为 升序排列
  • 1 <= k <= 104
  • k <= nums1.length * nums2.length

思路

首先需要明确的是,我们是需要找到最小的一对数,而最小的评定是两个数的加和最小

然后我们需要将nums1里的每个元素与nums2的第一个元素进行配对并计算和,然后放入最小堆中

接下来利用循环找到最小的k个对并弹出堆顶元素(最小配对)并添加到ans

接下来我们需要检查nums2是否有其他元素,有的话往下移然后继续匹配

代码

1
2
3
4
5
6
7
8
9
10
class Solution:
def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
ans = []
h = [(nums1[i] + nums2[0], i, 0) for i in range(min(len(nums1), k))]
while len(ans) < k:
_, i, j = heappop(h)
ans.append([nums1[i], nums2[j]])
if j + 1 < len(nums2):
heappush(h, (nums1[i] + nums2[j + 1], i, j + 1))
return ans

时间复杂度

时间复杂度O(k log k),空间复杂度O(k),执行时间139ms,消耗内存32.4MB


leetcode刷题记录——堆
https://www.lx02918.ltd/2024/09/11/leetcode-堆/
作者
Seth
发布于
2024年9月11日
许可协议