贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。 [1]
--------------------------------------------------------------------------------------------------------------------------------------------------摘自百度百科
1、现有一个字符数组,将字符数组中的所有字符串拼接起来,使得到的字符串字典序最小。
思路:使前两个拼接起来字典序最小,依次向后遍历。
注意:并不一定是字典序小的在前边,大的在后边,比如{ {ba} , {b} }, 显然并不是bba最小,而是bab。
public static String method(String[] strings) {
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String string1, String string2) {
return (string1 + string2).compareTo(string2 + string1);
}
};
Arrays.sort(strings, comparator);
StringBuilder stringBuilder = new StringBuilder();
for (String string : strings) {
stringBuilder.append(string);
}
return stringBuilder.toString();
}
2 、一块金条切成两半,是需要花费和长度数值一样的铜板的。比如长度为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铜板。
输入一个数组,返回分割的最小代价
思路:哈夫曼树问题
每次取出现有数据中最小的两个数。
public static int method(int[] arr) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
for (int num : arr) {
priorityQueue.add(num);
}
int res = 0;
while (priorityQueue.size() > 1) {
int cur = priorityQueue.poll() + priorityQueue.poll();
priorityQueue.add(cur);
res += cur;
}
return res;
}
3、IPO问题
现有两个数组cost[m], profile[m] 分别为 1~m-1 号项目的花费资金与完成项目后的纯利润。你的起始资金为n,你最多只能投资k个项目,同一时间只能投资一个项目。求你经过一段时间后最多所拥有的资金数。
思路:贪心:每次投资现有资金所能投资的收益最大的项目。
//项目类
static class Note {
int cost;
int profile;
public Note(int cost, int profile) {
this.cost = cost;
this.profile = profile;
}
}
public static int method(int[] cost, int[] profile, int k, int n) {
//将cost和profile封存到Note数组中
Note[] notes = new Note[cost.length];
for (int i = 0; i < cost.length; i++) {
notes[i] = new Note(cost[i], profile[i]);
}
//比较器,分别按cost从小到大,profile从大到小排列
PriorityQueue<Note> costMinPQ = new PriorityQueue<>((note1, note2) -> note1.cost - note2.cost);
PriorityQueue<Note> proMaxPQ = new PriorityQueue<>((note1, note2) -> note2.profile - note1.profile);
//将所有note添加到costMinPQ优先队列中
for (Note note : notes) {
costMinPQ.offer(note);
}
while (k-- > 0) {
//costMinPQ队列中,cost小于当前资金的,加入到proMaxPQ中
while (!costMinPQ.isEmpty() && costMinPQ.peek().cost <= n) {
Note note = costMinPQ.poll();
proMaxPQ.offer(note);
}
if (proMaxPQ.isEmpty()) {
return n;
}
//此时proMaxPq中弹出的就是当前资金所能作的收益最大的项目
n += proMaxPQ.poll().profile;
}
return n;
}
4、一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。 给你每一个项目开始的时间和结束的时间(给你一个数组,里面 是一个个具体的项目),你来安排宣讲的日程,要求会议室进行 的宣讲的场次最多。返回这个最多的宣讲场次。
思路:贪心,优先选择当前时间所能开的会议中,完成时间最早的。
public static int method(Note[] notes) {
Arrays.sort(notes, (note1, note2) -> note1.end - note2.end);
int cur = 0;
int res = 0;
for (int i = 0; i < notes.length; i++) {
if (cur < notes[i].begin) {
cur = notes[i].end;
res++;
}
}
return res;
}