贪心算法

贪心算法:从一个局部方向进行考虑,通过局部最优即可达到所要的整体最优,该方法就称作贪心算法

 

贪心算法的几道常见例题:
1.会议问题:已知一系列会议的起始时间和结束时间,在一段时间内合理安排会议,使这段时间可以尽可能多的会议
* 采用贪心算法策略:
* 即每次都选择大于当前时间内结束时间最早的那个会议

代码及解析:

 1 public static class Program{
 2         int begin;//会议开始时间
 3         int end;//会议结束时间
 4         
 5         public Program(int begin,int end) {
 6             this.begin = begin;
 7             this.end = end;
 8         }
 9     }
10     
11     public static class ProgramComparator implements Comparator<Program> {
12         public int compare(Program p1,Program p2) {
13             return p1.end - p2.end;
14         }
15     }
16     
17     
18     public static int bestArrange(Program[] programs,int timePoint) {
19         Arrays.sort(programs,new ProgramComparator());
20         int ans = 0;
21         for (int i = 0; i < programs.length; i++) {
22             if (timePoint <= programs[i].end) {
23                 ans++;
24                 timePoint = programs[i].end;
25             }
26         }
27         return ans;
28     }

 

2.最小字符串拼接:给定一个字符串数组,选择一种合适的拼接顺序,将字符串数组合成一个字典序最小的字符串

* 贪心算法策略:
* 1.一种错误策略:直接将字符串数组的每个字符串按字典序从小到大排列后,再依次进行拼接。
* 错误的反例:"ba"与"b",按照该策略则拼出字符串bba,但最优解是bab
* 2.正确的贪心算法策略:要比较字符串A和B谁先拼接,就先将两者分别拼接为AB和BA,如果AB字典序小,则说明
* A先拼接,反之则说明B先拼接(先拼接的就将其在排序中放在前面)

 

代码及解析:

 1 public static class StringComparator implements Comparator<String> {
 2         public int compare(String s1,String s2) {//重写字符串的比较器即可
 3             return (s1 + s2).compareTo(s2 + s1);
 4         }
 5     }
 6     
 7     public static String lowerString(String[] strs) {
 8         if (strs == null || strs.length == 0) {
 9             return null;
10         }
11         Arrays.sort(strs,new StringComparator());
12         String ans = "";
13         for (int i = 0; i < strs.length; i++) {
14             ans += strs[i];
15         }
16         return ans;
17     }

 

3.分割金条问题:有一根金条,将其分为长度确定的若干段,每次进行切割所花费的金钱等于所切割的金条的长度,选择一种方法,使得切割出金条后所花费的金钱最少

* 贪心算法策略:
* 因为要花的钱最少,所以每次尽量先把长的金条分出来,这可以让每次的金条长度减少量最多,使得后续花费更少
* 所以策略就是每次都切当前所需要的最长的金条即可。
*
* 为了便于编码解决问题,我们采用逆向思维进行思考:
* 将金条切割成若干段可以理解为将若干段金条合并成一整段金条,每次花费的代价就是合并出来的金条的代价。
* 所以为了花费的代价尽可能少,每次先把最短的两根金条先合并,最后再合并最长的金条

 

代码及解析:

 1 public static int lessSegCost(int[] arr) {
 2         PriorityQueue<Integer> pq = new PriorityQueue<>();
 3         int ans = 0;
 4         for (int i = 0; i < arr.length; i++) {
 5             pq.add(arr[i]);
 6         }
 7         while (pq.size() > 1) {
 8             int a = pq.poll();
 9             int b = pq.poll();
10             ans += a + b;
11             pq.add(a + b);//合并成的金条也是要放入优先队列中进行后续处理,不要遗漏
12         }
13         return ans;
14     }

 

4.投资项目问题:给定一系列项目,包含启动资金和项目利润,并给定能做的项目数,求能获得的最大利润

* 贪心算法:
* 即在力所能及(本金足够)的情况下,去做利润尽可能大的项目即可.

 

代码及解析:

 1 public static class Node{
 2         int cost;
 3         int profit;
 4         
 5         public Node(int cost,int profit) {
 6             this.cost = cost;
 7             this.profit = profit;
 8         }
 9     }
10     
11     public static class NodeComparator1 implements Comparator<Node> {//从开销小的项目开始找起
12         public int compare(Node n1,Node n2) {
13             return n1.cost - n2.cost;
14         }
15     }
16     
17     public static class NodeComparator2 implements Comparator<Node> {//在本金允许范围下,找高利润项目
18         public int compare(Node n1,Node n2) {
19             return n2.profit - n1.profit;
20         }
21     }
22     
23     public static int getMaxMoney(int W,int k,int[] cost,int[] profit) {
24         PriorityQueue<Node> minCost = new PriorityQueue<>(new NodeComparator1());
25         PriorityQueue<Node> maxProfit = new PriorityQueue<>(new NodeComparator2());
26         for (int i = 0; i < cost.length; i++) {
27             minCost.add(new Node(cost[i],profit[i]));
28         }
29         for (int i = 0; i < k; i++) {//最多可以做k个项目
30             //将本金允许的项目全部解锁
31             while (minCost.size() > 0 && minCost.peek().cost <= W) {
32                 maxProfit.add(minCost.poll());
33             }
34             if (maxProfit.size() == 0) {//当前本金已经没有项目可做了
35                 return W;
36             }
37             W += maxProfit.poll().profit;
38         }
39         return W;
40     }

 

posted @ 2022-04-20 10:14  jue1e0  阅读(153)  评论(0)    收藏  举报