LeetCode: 502. IPO

554 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情

502. IPO

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ip…

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

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

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

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

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

示例 1:

输入: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:

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

提示:

  • 1 <= k <= 10510^5
  • 0 <= w <= 10910^9
  • n == profits.length
  • n == capital.length
  • 1 <= n <= 10510^5
  • 0 <= profits[i] <= 10410^4
  • 0 <= capital[i] <= 10910^9

解法

思路:如果人自己去考虑如何选择,首先是根据当前的资金取所有够启动资金中收益最大的去做,做完之后,可做的项目可能会有扩充,在扩充后的项目中再取收益最大的做,直到做完限定数目的项目。

这是贪心的思想。“候选可做项目”可以用最大堆存储,每次弹出最大收益的项目。

具体思路: 根据启动资金倒序排列,把当前所有能做的项目的收益放到大根堆中,取堆顶就是可以做的项目;只要有新的可以做的项目都首先放到堆中; 直到取到了k个项目,结束遍历,返回结果;

  • python
from heapq import *

class Solution:
    def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
        n = len(profits)
        if w > max(capital):
            return w + sum(nlargest(k, profits))  # nlargest nsmallest
        
        
        curr = 0
        arr = [(capital[i], profits[i]) for i in range(n)]
        arr.sort(key=lambda x: x[0])
        pq = []

        for _ in range(k):
            while curr < n and arr[curr][0] <= w:
                heappush(pq, -arr[curr][1]) # -值最小堆变最大堆 
                curr += 1
            
            if pq:  # 非空取第一个值
                w -= heappop(pq)
            else:
                break
        return w
  • c++
typedef pair<int,int> pii;

class Solution {
public:
    int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {
        int n = profits.size();
        int curr = 0;

        priority_queue<int, vector<int>, less<int>> pq;  // 降序排序
        vector<pii> arr;

        for(int i=0; i<n; i++)
        {
            arr.push_back({capital[i], profits[i]});
        }

        sort(arr.begin(), arr.end());

        for(int i=0; i<k; i++)
        {
            while(curr<n && arr[curr].first <= w)
            {
             pq.push(arr[curr].second);
             curr += 1;   
            }

            if(!pq.empty())
            {
                w += pq.top();
                pq.pop();
            }
            else
            {
                break;
            }
        }

    return w;
    }
};

复杂度分析

  • 时间复杂度:O((n+k)logn)O((n + k) log n)

    • O(nlog n)的时间复杂度来来创建和排序项目,往堆中添加元素的时间不超过 O(nlogn)
    • 每次从堆中取出最大值并更新资本的时间为O(klogn)
  • 空间复杂度:O(n)O(n),空间复杂度主要取决于创建用于排序的数组和大根堆