贪心算法的特点:
最自然智慧的算法
用一种局部最功利的标准,总是做出在当前看来是最好的选择。
难点在于证明局部最功利的标准可以得到全局最优解,实际解题过程中不要纠结贪心策略的证明,用对数器去验证贪心策略的正确性
对于贪心算法的学习主要以增加阅历和经验为主
堆和排序是贪心算法最常用的两个技巧。
最小字典序 给定一个由字符串组成的数组strs,把所有的字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static class MyComparator implements Comparator <String > { @Override public int compare (String a, String b) { return (a + b).compareTo(b + a); } } public static String lowestString (String[] strs) { if (strs == null || strs.length == 0 ) { return "" ; } Arrays.sort(strs, new MyComparator()); String res = "" ; for (int i = 0 ; i < strs.length; i++) { res += strs[i]; } return res; }
会议室最多宣讲场次 一些项目想要占用一个会议室宣讲,会议室同一时间只能容纳一个宣讲,给定每个项目宣讲的开始时间和结束时间,要求合理安排宣讲日程使得会议室进行的宣讲场次最多,返回最多的宣讲场次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public static class Program { public int start; public int end; public Program (int start, int end) { this .start = start; this .end = end; } } public static int bestArrange (Program[] programs) { Arrays.sort(programs, new ProgramComparator()); int timeLine = 0 ; int result = 0 ; for (int i = 0 ; i < programs.length; i++) { if (timeLine <= programs[i].start) { result++; timeLine = programs[i].end; } } return result; } public static class ProgramComparator implements Comparator <Program > { @Override public int compare (Program o1, Program o2) { return o1.end - o2.end; } }
最小代价分金(哈夫曼编码问题) 一块金条切成两半,需要花费和长度相同的铜板。如果长度为20的金条不管怎么切都要花费20个铜板。
例如:给定数组{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。
一群人想要整分整块金条,怎么分割代价最小?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static int lessMoney (int [] arr) { PriorityQueue<Integer> pQ = new PriorityQueue<>(); for (int i = 0 ; i < arr.length; i++) { pQ.add(arr[i]); } int sum = 0 ; int cur = 0 ; while (pQ.size() > 1 ) { cur = pQ.poll() + pQ.poll(); sum += cur; pQ.add(cur); } return sum; }
项目安排最大利润 输入:正数数组costs、正数数组profits、正数K、正数M
costs[i] 表示 i 号项目的花费
profits[i] 表示 i 号项目在扣除花费之后的利润
K 表示最多能串行的做 K 个项目
W 表示初始资金
说明:每做完一个项目,马上就能获得收益,可以支持去做下一个项目。不能并行做项目。
要求:输出可以获得的最大钱数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public static int findMaximizedCapital (int K, int W, int [] Profits, int [] Capital) { PriorityQueue<Program> minCostQ = new PriorityQueue<>(new MinCostComparator()); PriorityQueue<Program> maxProfitQ = new PriorityQueue<>(new MaxProfitComparator()); for (int i = 0 ; i < Profits.length; i++) { minCostQ.add(new Program(Profits[i], Capital[i])); } for (int i = 0 ; i < K; i++) { while (!minCostQ.isEmpty() && minCostQ.peek().c <= W) { maxProfitQ.add(minCostQ.poll()); } if (maxProfitQ.isEmpty()) { return W; } W += maxProfitQ.poll().p; } return W; } public static class Program { public int p; public int c; public Program (int p, int c) { this .p = p; this .c = c; } } public static class MinCostComparator implements Comparator <Program > { @Override public int compare (Program o1, Program o2) { return o1.c - o2.c; } } public static class MaxProfitComparator implements Comparator <Program > { @Override public int compare (Program o1, Program o2) { return o2.p - o1.p; } }
点灯问题 给定一个字符串str,只由 ‘X’ 和 ‘.’ 两种字符构成。
‘X’ 表示墙,不能放灯也不需要点亮
‘.’ 表示民居,可以放灯,需要点亮
如果灯放在 i 位置,可以让 i-1,i 和 i+1 三个位置被点亮。
要求返回如果点亮str中所有需要点亮的位置,至少需要几盏灯?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static int minLight (String road) { char [] str = road.toCharArray(); int i = 0 ; int light = 0 ; while (i < str.length) { if (str[i] == 'X' ) { i++; } else { light++; if (i + 1 == str.length) { break ; } else { if (str[i + 1 ] == 'X' ) { i = i + 2 ; } else { i = i + 3 ; } } } } return light; }