题目来源:https://leetcode-cn.com/problems/ipo/
大致题意:
给定一个初始资本 w,和可以投资的项目数 k,以及项目对应的资本数组 capital 和 利润数组 profits。
返回投资可以获得的最大资本。
思路
每次项目的利润可以直接加入资本,称为新的资本值。那么肯定是想要在可以做的项目做利润最高的项目。
显然是一个贪心的过程。
堆排序 + 贪心
分析:
- 可以做的项目,即为所需资本不大于当前资本的项目
- 然后在可以做的项目选择利润最大的最大
解决:
- 使用一个二维数组 cp,第一维大小即为 资本数组的大小(和利润数组大小一致),第二位大小为 2,存下对应的资本和利润。然后对数组按照资本的大小进行排序。
- 使用一个索引,标记当前资本可以入手的项目位置,那么在当前索引位置之前的所有元素,也就是对应的项目的资本都不大于当前资本
- 使用一个大根堆,存下可入手的项目对应的资本,只需存下资本值。
- 遍历 k 次,每次取出堆顶的利润,加入总资本中。注意,若当前堆为空,代表没有可以入手的项目,即当前资本小于剩下的项目中所需资本的最小值,直接退出循环。
代码:
public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) {
int[][] cp = new int[profits.length][2]; // 存下对应的利润和资本
for (int i = 0; i < profits.length; i++) {
cp[i][0] = capital[i];
cp[i][1] = profits[i];
}
// 按照资本升序排序
Arrays.sort(cp, (a, b) -> a[0] - b[0]);
// 建立一个大根堆
PriorityQueue<Integer> queue = new PriorityQueue<Integer>((a, b) -> b - a);
int x = 0; // 用来记录当前数组 cp 的遍历位置
// 进行 k 次最优选择
// 即选择当前资本可以完成的最大项目
for (int i = 0; i < k; i++) {
// 若当前资本大于 cp 当前位置所需资本,入堆
while (x < cp.length && w >= cp[x][0]) {
queue.offer(cp[x++][1]);
}
// 堆不为空,证明有可以完成的项目
if (!queue.isEmpty()) {
w += queue.poll();
}
// 堆为空,没有可以入手的项目,直接退出
else {
break;
}
}
return w;
}