「每日一题」IPO

该博客介绍了如何解决LeetCode上的IPO问题,通过贪心策略选择投资项目以最大化最终资本。首先,将项目按所需资本从小到大排序,然后创建一个最大堆,依次将满足条件的项目利润插入堆中。每次从堆中取出最大利润并更新资本,重复此过程最多k次。最后返回最大资本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是 LeetCode 上 2021-9-8 的每日一题:「502. IPO」

1. 题目描述

假设 力扣(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

2. 解答

贪心思想:每次投资的项目的纯利润要最大

  1. 先获得项目数组arr,将资本、利润按项目号组合
  2. 将项目按所需资本从小到大排序(若从大到小,可能一开始就没法投资了)
  3. 将所有满足条件的项目所获得的利润插入最大堆
  4. 若堆不为空,取出堆顶,即为最大的纯利润,更新自己的资本w
  5. 若堆为空,直接退出循环,因为当前已经没有满足条件的项目进入堆了
  6. 重复步骤 3~5,一共执行k
  7. 最后返回最终的资本w
// 默认最大堆
const defaultCmp = (x, y) => x > y;
// 交换元素
const swap = (arr, i, j) => ([arr[i], arr[j]] = [arr[j], arr[i]]);
// 堆类,默认最大堆
class Heap {
    constructor(cmp = defaultCmp) {
        this.container = [];
        this.cmp = cmp;
    }
    // 插入
    insert(data) {
        const { container, cmp } = this;
        container.push(data);
        let index = this.size() - 1;
        while (index) {
            let parent = (index - 1) >> 1;
            if (!cmp(container[index], container[parent])) {
                return;
            }
            swap(container, index, parent);
            index = parent;
        }
    }
    // 弹出堆顶,并返回
    pop() {
        const { container, cmp } = this;
        if (!this.size()) {
            return null;
        }

        swap(container, 0, this.size() - 1);
        const res = container.pop();
        const length = this.size();
        let index = 0,
            exchange = index * 2 + 1;

        while (exchange < length) {
            // // 以最大堆的情况来说:如果有右节点,并且右节点的值大于左节点的值
            let right = index * 2 + 2;
            if (right < length && cmp(container[right], container[exchange])) {
                exchange = right;
            }
            if (!cmp(container[exchange], container[index])) {
                break;
            }
            swap(container, exchange, index);
            index = exchange;
            exchange = index * 2 + 1;
        }

        return res;
    }
    // 获取堆大小
    size() {
        return this.container.length;
    }
}

const findMaximizedCapital = (k, w, profits, capital) => {
    const n = profits.length;
    const arr = new Array(n);
    // 将资本、利润按项目号组合   [资本,纯利润]
    for (let i = 0; i < n; i++) {
        arr[i] = [capital[i], profits[i]];
    }
    // 将项目按所需资本从小到大排序
    arr.sort((a, b) => a[0] - b[0]);

    // 创建最大堆
    const maxHeap = new Heap();
    let cur = 0;
    for (let i = 0; i < k; i++) {
        while (cur < n && arr[cur][0] <= w) {
            // 将所有满足条件的项目所获得的利润插入堆中
            maxHeap.insert(arr[cur++][1]);
        }
        if (maxHeap.size()) {
            // 堆不为空
            // 取出堆顶,即为最大的纯利润,更新自己的资本w
            w += maxHeap.pop();
        } else {
            // 堆为空,直接退出循环
            // 因为已经没有满足条件的项目进入堆了
            break;
        }
    }
    return w;
};

😄最近新创建了个开源仓库,总结 LeetCode 的每日一题,目前已有 C++、JavaScript 语言版本,欢迎大家提供其他语言版本!

🖥️仓库地址:「每日一题系列」

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值