经典的哈夫曼编码问题:
一块金条切成两半, 是需要花费和长度数值一样的铜板的。 比如长度为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铜板。
输入一个数组, 返回分割的最小代价
哈夫曼编码贪心策略:
将数组中的所有数扔进小根堆,每次取出最小的两个求和,将和再扔进小根堆.以此类推,直到堆中只剩下一个元素停止.所有取出元素后生成的和就是全部的切割金条的代价.相加可得总代价.
当一个事务的总代价是其子集的代价通过相乘相加等一系列计算得到的情况下,都可以用哈夫曼编码贪心得到.
代码如下:
import java.util.PriorityQueue;
public class Greed {
public static void main(String[] args) {
int [] arr = new int [] {1,4,7,2,5,8,3,6,9};
int res = huffman(arr);
System.out.println(res);
}
public static Integer huffman(int [] arr){
PriorityQueue<Integer> pQ = new PriorityQueue<Integer>();
for(int i = 0; i < arr.length; i++){
pQ.add(arr[i]);
}
int res = 0;
int cur = 0;
while(pQ.size() > 1){
cur = pQ.poll() + pQ.poll();
res += cur;
pQ.add(cur);
}
return res;
}
}
在Java中,priorityQueue就是堆的一种实现,其默认按照自然顺序排序且没有容量界限.它可以保证每次弹出的数据是堆中最小的,所以我们可以将其当做小根堆使用.
要注意:默认的PriorityQueue并非保证了整个队列都是有序的,只是保证了队头是最小的
除了默认方式,我们可以通过构建PriorityQueue时传入比较器的办法来决定将其构建成大根堆或小根堆.,代码如下:
public static void main(String [] args){
PriorityQueue<Integer> minQ2 = new PriorityQueue<>(new MinheapComparator());
}
public static class MyMinComparator implements Comparator<Integer> {
@Override
public int compare(Integer num1, Integer num2) {
return num1- num2;
}
}