Huffman Encoding
Problem Statement
Given characters and their frequencies, construct a Huffman code (variable-length prefix code) to minimize total encoding length. This hard-level greedy problem is about compression—encode efficiently!
Example
Input: chars = ['a', 'b', 'c'], freq = [5, 9, 12]
Output: {'a': '00', 'b': '1', 'c': '01'} (length = 5*2 + 9*1 + 12*2 = 43)
Input: chars = ['a', 'b'], freq = [1, 1]
Output: {'a': '0', 'b': '1'}
Code
Java
Python
JavaScript
import java.util.*;
public class Solution {
class Node {
char ch; int freq; Node left, right;
Node(char ch, int freq) { this.ch = ch; this.freq = freq; }
}
public Map huffmanEncoding(char[] chars, int[] freq) {
PriorityQueue pq = new PriorityQueue<>((a, b) -> a.freq - b.freq);
for (int i = 0; i < chars.length; i++) pq.add(new Node(chars[i], freq[i]));
while (pq.size() > 1) {
Node left = pq.poll();
Node right = pq.poll();
Node parent = new Node('\0', left.freq + right.freq);
parent.left = left; parent.right = right;
pq.add(parent);
}
Map codes = new HashMap<>();
generateCodes(pq.peek(), "", codes);
return codes;
}
private void generateCodes(Node root, String code, Map codes) {
if (root == null) return;
if (root.left == null && root.right == null) codes.put(root.ch, code);
generateCodes(root.left, code + "0", codes);
generateCodes(root.right, code + "1", codes);
}
}
from heapq import heappush, heappop
class Node:
def __init__(self, ch, freq): self.ch, self.freq, self.left, self.right = ch, freq, None, None
def __lt__(self, other): return self.freq < other.freq
def huffman_encoding(chars, freq):
pq = []
for ch, f in zip(chars, freq): heappush(pq, Node(ch, f))
while len(pq) > 1:
left = heappop(pq)
right = heappop(pq)
parent = Node(None, left.freq + right.freq)
parent.left, parent.right = left, right
heappush(pq, parent)
codes = {}
def generate_codes(node, code=""):
if not node: return
if not node.left and not node.right: codes[node.ch] = code
generate_codes(node.left, code + "0")
generate_codes(node.right, code + "1")
generate_codes(pq[0])
return codes
class Node {
constructor(ch, freq) { this.ch = ch; this.freq = freq; this.left = null; this.right = null; }
}
function huffmanEncoding(chars, freq) {
let pq = [];
for (let i = 0; i < chars.length; i++) pq.push(new Node(chars[i], freq[i]));
pq.sort((a, b) => a.freq - b.freq);
while (pq.length > 1) {
let left = pq.shift();
let right = pq.shift();
let parent = new Node(null, left.freq + right.freq);
parent.left = left; parent.right = right;
pq.push(parent); pq.sort((a, b) => a.freq - b.freq);
}
let codes = {};
function generateCodes(node, code = "") {
if (!node) return;
if (!node.left && !node.right) codes[node.ch] = code;
generateCodes(node.left, code + "0");
generateCodes(node.right, code + "1");
}
generateCodes(pq[0]);
return codes;
}
Explanation
- Greedy Choice: Combine two lowest-frequency nodes iteratively.
- Flow: Build a tree, assign codes via traversal.
- Example: ['a',5],['b',9],['c',12] → combine 5+9, then with 12.
Note
Time complexity: O(n log n), Space complexity: O(n). Compress like a pro!
