题目一
一块金条切成两半,是需要花费和长度数值一样的铜板的。比如长度为20的 金条,不管切成长度多大的两半,都要花费20个铜板。一群人想整分整块金 条,怎么分最省铜板?
例如,给定数组{10,20,30},代表一共三个人,整块金条长度为10+20+30=60. 金条要分成10,20,30三个部分。 如果, 先把长度60的金条分成10和50,花费60 再把长度50的金条分成20和30,花费50 一共花费110铜板。但是如果, 先把长度60的金条分成30和30,花费60 再把长度30金条分成10和20,花费30 一共花费90铜板。输入一个数组,返回分割的最小代价。
思想:经典的贪心算法,用小根堆来做:
首先根据给定的数组构造小根堆,每次poll出两个数据,然后将两数据之和相加后放回小根堆,整个过程中所有非叶子节点之和就是所求的最小代价,这也是一个标准的哈夫曼编码问题。
public class LessMoney {
public static class MinHeapComparator implements Comparator<Integer>{
public int compare(Integer o1,Integer o2){
return o1-o2;
}
}
public static int lessMoney(int[] arr){
PriorityQueue<Integer> minHeap=new PriorityQueue<>(new MinHeapComparator());
for(int i:arr){
minHeap.add(i);
}
int sum=0;
while(minHeap.size()>1){
int add=minHeap.poll()+minHeap.poll();
sum+=add;
minHeap.add(add);
}
return sum;
}
public static void main(String[] args){
int[] arr={10,20,30};
System.out.println(lessMoney(arr));
}
}
- 题目二
假设 力扣(LeetCode)即将开始其 IPO。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后得到最大总资本的方式。
给定若干个项目。对于每个项目 i,它都有一个纯利润 Pi,并且需要最小的资本 Ci 来启动相应的项目。最初,你有 W 资本。当你完成一个项目时,你将获得纯利润,且利润将被添加到你的总资本中。
总而言之,从给定项目中选择最多 k 个不同项目的列表,以最大化最终资本,并输出最终可获得的最多资本。
示例 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。
注意:
假设所有输入数字都是非负整数。
表示利润和资本的数组的长度不超过 50000。
答案保证在 32 位有符号整数范围内。
算法思想:
根据项目cost来构建小根堆,如果初始资本>cost,则依次弹出项目,根据profit构建大根堆,每次要做的项目从大根堆拿出来;直到项目数目满足条件或者大根堆为空,终止,返回最后的w.
public class IPO {
public static class Node{
private int cost;
private int profit;
public Node(int cost,int profit){
this.cost=cost;
this.profit=profit;
}
}
public static class minCostComparator implements Comparator<Node>{
public int compare(Node o1,Node o2){
return o1.cost-o2.cost;
}
}
public static class maxProfitComparator implements Comparator<Node>{
public int compare(Node o1,Node o2){
return o2.profit-o1.profit;
}
}
public static int maxProfit(int[] cost,int[] profit,int w,int k){
Node[] nodes=new Node[profit.length];
PriorityQueue<Node> minCostQueue=new PriorityQueue<>(new minCostComparator());
PriorityQueue<Node> maxProfitQueue=new PriorityQueue<>(new maxProfitComparator());
for(int i=0;i<profit.length;i++){
nodes[i]=new Node(cost[i],profit[i]); //构建项目节点数组
minCostQueue.add(nodes[i]);//构建小根堆
}
for(int i=0;i<k;i++){
//如果当前项目可以做,依次弹出;构建大根堆
while(!minCostQueue.isEmpty()&&minCostQueue.peek().cost<=w){
maxProfitQueue.add(minCostQueue.poll());
}
if(maxProfitQueue.isEmpty()){ //当前获得的w总和不够开启下一次项目
return w;
}
w+=maxProfitQueue.poll().profit;//做完一次项目,将profit累加
}
return w;
}
}
- 题目三
一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目 的宣讲。 给你每一个项目开始的时间和结束的时间(给你一个数组,里面 是一个个具体的项目),你来安排宣讲的日程,要求会议室进行 的宣讲的场次最多。返回这个最多的宣讲场次。
算法思想:
这里关键是贪心策略的选择:
①哪个项目早,就开始哪个项目,很容易举出反例,不正确;
②哪个项目持续时间短就开始哪个项目,也可以举出反例,不正确;
③哪个项目结束时间短,就开始哪个项目(正确的贪心策略)
public class BeatArranges {
public static class Programs{
private int start;
private int end;
public Programs(int start,int end){
this.start=start;
this.end=end;
}
}
public static class EarliestEndComparator implements Comparator<Programs>{
public int compare(Programs o1,Programs o2){
return o1.end-o2.end;//这里的贪心策略按照哪个项目结束时间早,就做哪个项目
}
}
public static int MaxPrograms(Programs[] programs,int currentTime){
Arrays.sort(programs,new EarliestEndComparator());
int count=0;
for(int i=0;i<programs.length;i++){
if(currentTime<=programs[i].start){
count++;
currentTime=programs[i].end;
}
}
return count;
}
public static void main(String[] args){
}
}