Skip to main content

algorithms_lib/
lib.rs

1//! Algorithms Library for Rust
2//!
3//! A comprehensive, zero-dependency collection of common algorithms.
4
5use std::cmp::Ordering;
6use std::cmp::Reverse;
7use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
8use std::error::Error as StdError;
9use std::fmt;
10
11/// Errors that can be returned by algorithms in this crate.
12#[derive(Debug, Clone, PartialEq)]
13pub enum Error {
14    NotFound,
15    InvalidInput,
16    InvalidGraph,
17    NegativeCycle,
18}
19
20impl fmt::Display for Error {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            Error::NotFound => write!(f, "not found"),
24            Error::InvalidInput => write!(f, "invalid input"),
25            Error::InvalidGraph => write!(f, "invalid graph"),
26            Error::NegativeCycle => write!(f, "negative-weight cycle detected"),
27        }
28    }
29}
30
31impl StdError for Error {}
32
33// ---------------- Sorting ----------------
34
35/// Quick sort.
36pub fn quick_sort<T: Ord + Clone>(items: &[T]) -> Vec<T> {
37    if items.len() <= 1 {
38        return items.to_vec();
39    }
40    let pivot = items[items.len() / 2].clone();
41    let mut left = Vec::new();
42    let mut middle = Vec::new();
43    let mut right = Vec::new();
44    for x in items {
45        if *x < pivot {
46            left.push(x.clone());
47        } else if *x > pivot {
48            right.push(x.clone());
49        } else {
50            middle.push(x.clone());
51        }
52    }
53    let mut result = quick_sort(&left);
54    result.extend(middle);
55    result.extend(quick_sort(&right));
56    result
57}
58
59/// Stable merge sort.
60pub fn merge_sort<T: Ord + Clone>(items: &[T]) -> Vec<T> {
61    if items.len() <= 1 {
62        return items.to_vec();
63    }
64    let mid = items.len() / 2;
65    let left = merge_sort(&items[..mid]);
66    let right = merge_sort(&items[mid..]);
67    merge(&left, &right)
68}
69
70fn merge<T: Ord>(left: &[T], right: &[T]) -> Vec<T>
71where
72    T: Clone,
73{
74    let mut merged = Vec::with_capacity(left.len() + right.len());
75    let mut i = 0;
76    let mut j = 0;
77    while i < left.len() && j < right.len() {
78        if left[i] <= right[j] {
79            merged.push(left[i].clone());
80            i += 1;
81        } else {
82            merged.push(right[j].clone());
83            j += 1;
84        }
85    }
86    merged.extend_from_slice(&left[i..]);
87    merged.extend_from_slice(&right[j..]);
88    merged
89}
90
91/// Binary max-heap sort.
92pub fn heap_sort<T: Ord + Clone>(items: &[T]) -> Vec<T> {
93    let mut arr = items.to_vec();
94    let n = arr.len();
95    if n <= 1 {
96        return arr;
97    }
98    for i in (0..n / 2).rev() {
99        sift_down(&mut arr, n, i);
100    }
101    for end in (1..n).rev() {
102        arr.swap(0, end);
103        sift_down(&mut arr, end, 0);
104    }
105    arr
106}
107
108fn sift_down<T: Ord>(arr: &mut [T], n: usize, i: usize) {
109    let mut largest = i;
110    let left = 2 * i + 1;
111    let right = 2 * i + 2;
112    if left < n && arr[left] > arr[largest] {
113        largest = left;
114    }
115    if right < n && arr[right] > arr[largest] {
116        largest = right;
117    }
118    if largest != i {
119        arr.swap(i, largest);
120        sift_down(arr, n, largest);
121    }
122}
123
124/// LSD radix sort for non-negative integers.
125pub fn radix_sort(items: &[i64]) -> Result<Vec<i64>, Error> {
126    if items.is_empty() {
127        return Ok(Vec::new());
128    }
129    for &v in items {
130        if v < 0 {
131            return Err(Error::InvalidInput);
132        }
133    }
134    let mut arr = items.to_vec();
135    let mut max_val = arr[0];
136    for &v in &arr {
137        if v > max_val {
138            max_val = v;
139        }
140    }
141    let mut exp = 1;
142    while max_val / exp > 0 {
143        counting_sort_by_digit(&mut arr, exp);
144        exp *= 10;
145    }
146    Ok(arr)
147}
148
149fn counting_sort_by_digit(arr: &mut [i64], exp: i64) {
150    let n = arr.len();
151    let mut output = vec![0; n];
152    let mut count = vec![0; 10];
153    for &num in arr.iter() {
154        count[((num / exp) % 10) as usize] += 1;
155    }
156    for i in 1..10 {
157        count[i] += count[i - 1];
158    }
159    for i in (0..n).rev() {
160        let index = ((arr[i] / exp) % 10) as usize;
161        output[count[index] - 1] = arr[i];
162        count[index] -= 1;
163    }
164    arr.copy_from_slice(&output);
165}
166
167/// Standard-library sort (Timsort-like).
168pub fn tim_sort<T: Ord + Clone>(items: &[T]) -> Vec<T> {
169    let mut arr = items.to_vec();
170    arr.sort();
171    arr
172}
173
174// ---------------- Searching ----------------
175
176fn check_sorted<T: Ord>(arr: &[T]) -> Result<(), Error> {
177    for i in 1..arr.len() {
178        if arr[i] < arr[i - 1] {
179            return Err(Error::InvalidInput);
180        }
181    }
182    Ok(())
183}
184
185/// Binary search.
186pub fn binary_search<T: Ord>(arr: &[T], target: &T) -> Result<usize, Error> {
187    check_sorted(arr)?;
188    let mut lo = 0;
189    let mut hi = arr.len() as isize - 1;
190    while lo <= hi {
191        let mid = (lo + hi) / 2;
192        let mid_usize = mid as usize;
193        if &arr[mid_usize] == target {
194            return Ok(mid_usize);
195        }
196        if &arr[mid_usize] < target {
197            lo = mid + 1;
198        } else {
199            hi = mid - 1;
200        }
201    }
202    Err(Error::NotFound)
203}
204
205/// Interpolation search for numeric data.
206pub fn interpolation_search(arr: &[i64], target: i64) -> Result<usize, Error> {
207    check_sorted(arr)?;
208    let mut lo = 0;
209    let mut hi = arr.len() as isize - 1;
210    while lo <= hi && target >= arr[lo as usize] && target <= arr[hi as usize] {
211        if arr[hi as usize] == arr[lo as usize] {
212            if arr[lo as usize] == target {
213                return Ok(lo as usize);
214            }
215            break;
216        }
217        let lo_usize = lo as usize;
218        let hi_usize = hi as usize;
219        let pos = lo_usize
220            + ((target - arr[lo_usize]) as f64 / (arr[hi_usize] - arr[lo_usize]) as f64
221                * (hi_usize - lo_usize) as f64) as usize;
222        if pos < lo_usize || pos > hi_usize {
223            break;
224        }
225        if arr[pos] == target {
226            return Ok(pos);
227        }
228        if arr[pos] < target {
229            lo = pos as isize + 1;
230        } else {
231            hi = pos as isize - 1;
232        }
233    }
234    Err(Error::NotFound)
235}
236
237/// Jump search.
238pub fn jump_search<T: Ord>(arr: &[T], target: &T) -> Result<usize, Error> {
239    check_sorted(arr)?;
240    let n = arr.len();
241    if n == 0 {
242        return Err(Error::NotFound);
243    }
244    let mut step = (n as f64).sqrt() as usize;
245    if step == 0 {
246        step = 1;
247    }
248    let mut prev = 0;
249    while arr[step.min(n) - 1] < *target {
250        prev = step;
251        step += (n as f64).sqrt() as usize;
252        if prev >= n {
253            return Err(Error::NotFound);
254        }
255    }
256    while arr[prev] < *target {
257        prev += 1;
258        if prev == step.min(n) {
259            return Err(Error::NotFound);
260        }
261    }
262    if &arr[prev] == target {
263        return Ok(prev);
264    }
265    Err(Error::NotFound)
266}
267
268// ---------------- Graphs ----------------
269
270/// Weighted edge for graph algorithms.
271#[derive(Debug, Clone, PartialEq)]
272pub struct Edge {
273    pub to: String,
274    pub weight: f64,
275}
276
277impl Edge {
278    pub fn new(to: &str, weight: f64) -> Self {
279        Edge {
280            to: to.to_string(),
281            weight,
282        }
283    }
284}
285
286/// Breadth-first search.
287pub fn bfs(graph: &HashMap<String, Vec<String>>, start: &str) -> Result<Vec<String>, Error> {
288    if !graph.contains_key(start) {
289        return Err(Error::InvalidGraph);
290    }
291    let mut visited = HashSet::new();
292    visited.insert(start.to_string());
293    let mut queue = VecDeque::new();
294    queue.push_back(start.to_string());
295    let mut result = Vec::new();
296    while let Some(current) = queue.pop_front() {
297        result.push(current.clone());
298        if let Some(neighbors) = graph.get(&current) {
299            for nbr in neighbors {
300                if visited.insert(nbr.clone()) {
301                    queue.push_back(nbr.clone());
302                }
303            }
304        }
305    }
306    Ok(result)
307}
308
309/// Depth-first search.
310pub fn dfs(graph: &HashMap<String, Vec<String>>, start: &str) -> Result<Vec<String>, Error> {
311    if !graph.contains_key(start) {
312        return Err(Error::InvalidGraph);
313    }
314    let mut visited = HashSet::new();
315    visited.insert(start.to_string());
316    let mut stack = vec![start.to_string()];
317    let mut result = Vec::new();
318    while let Some(current) = stack.pop() {
319        result.push(current.clone());
320        if let Some(neighbors) = graph.get(&current) {
321            for nbr in neighbors.iter().rev() {
322                if visited.insert(nbr.clone()) {
323                    stack.push(nbr.clone());
324                }
325            }
326        }
327    }
328    Ok(result)
329}
330
331#[derive(Clone)]
332struct State {
333    cost: f64,
334    node: String,
335}
336
337impl PartialEq for State {
338    fn eq(&self, other: &Self) -> bool {
339        self.cost.total_cmp(&other.cost) == Ordering::Equal && self.node == other.node
340    }
341}
342
343impl Eq for State {}
344
345impl PartialOrd for State {
346    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
347        Some(self.cmp(other))
348    }
349}
350
351impl Ord for State {
352    fn cmp(&self, other: &Self) -> Ordering {
353        other
354            .cost
355            .total_cmp(&self.cost)
356            .then_with(|| self.node.cmp(&other.node))
357    }
358}
359
360/// Dijkstra's shortest paths.
361pub fn dijkstra(
362    graph: &HashMap<String, Vec<Edge>>,
363    start: &str,
364) -> Result<(HashMap<String, f64>, HashMap<String, String>), Error> {
365    if !graph.contains_key(start) {
366        return Err(Error::InvalidGraph);
367    }
368    let mut distances: HashMap<String, f64> =
369        graph.keys().map(|k| (k.clone(), f64::INFINITY)).collect();
370    distances.insert(start.to_string(), 0.0);
371    let mut predecessors = HashMap::new();
372
373    let mut pq = BinaryHeap::new();
374    pq.push(State {
375        cost: 0.0,
376        node: start.to_string(),
377    });
378
379    while let Some(State { cost, node }) = pq.pop() {
380        if cost != distances[&node] {
381            continue;
382        }
383        for e in graph.get(&node).unwrap_or(&Vec::new()) {
384            if e.weight < 0.0 {
385                return Err(Error::InvalidGraph);
386            }
387            let nd = cost + e.weight;
388            let current = distances.get(&e.to).copied().unwrap_or(f64::INFINITY);
389            if nd < current {
390                distances.insert(e.to.clone(), nd);
391                predecessors.insert(e.to.clone(), node.clone());
392                pq.push(State {
393                    cost: nd,
394                    node: e.to.clone(),
395                });
396            }
397        }
398    }
399    Ok((distances, predecessors))
400}
401
402/// A* shortest path.
403pub fn a_star<F>(
404    graph: &HashMap<String, Vec<Edge>>,
405    start: &str,
406    goal: &str,
407    heuristic: F,
408) -> Result<(Vec<String>, f64), Error>
409where
410    F: Fn(&str, &str) -> f64,
411{
412    if !graph.contains_key(start) || !graph.contains_key(goal) {
413        return Err(Error::InvalidGraph);
414    }
415    let mut g_score = HashMap::new();
416    g_score.insert(start.to_string(), 0.0);
417    let mut came_from = HashMap::new();
418    let mut pq = BinaryHeap::new();
419    pq.push(State {
420        cost: heuristic(start, goal),
421        node: start.to_string(),
422    });
423
424    while let Some(State { cost: _, node }) = pq.pop() {
425        if node == goal {
426            return Ok((reconstruct_path(&came_from, &node), g_score[goal]));
427        }
428        for e in graph.get(&node).unwrap_or(&Vec::new()) {
429            let tentative = g_score[&node] + e.weight;
430            let current = g_score.get(&e.to).copied().unwrap_or(f64::INFINITY);
431            if tentative < current {
432                came_from.insert(e.to.clone(), node.clone());
433                g_score.insert(e.to.clone(), tentative);
434                pq.push(State {
435                    cost: tentative + heuristic(&e.to, goal),
436                    node: e.to.clone(),
437                });
438            }
439        }
440    }
441    Err(Error::NotFound)
442}
443
444fn reconstruct_path(came_from: &HashMap<String, String>, start: &str) -> Vec<String> {
445    let mut current = start.to_string();
446    let mut path = vec![current.clone()];
447    while let Some(prev) = came_from.get(&current) {
448        path.push(prev.clone());
449        current = prev.clone();
450    }
451    path.reverse();
452    path
453}
454
455struct Edge3 {
456    from: String,
457    to: String,
458    weight: f64,
459}
460
461/// Bellman-Ford shortest paths with negative cycle detection.
462pub fn bellman_ford(
463    graph: &HashMap<String, Vec<Edge>>,
464    start: &str,
465) -> Result<(HashMap<String, f64>, HashMap<String, String>), Error> {
466    if !graph.contains_key(start) {
467        return Err(Error::InvalidGraph);
468    }
469    let mut vertices = HashSet::new();
470    let mut edges = Vec::new();
471    for (u, list) in graph {
472        vertices.insert(u.clone());
473        for e in list {
474            vertices.insert(e.to.clone());
475            edges.push(Edge3 {
476                from: u.clone(),
477                to: e.to.clone(),
478                weight: e.weight,
479            });
480        }
481    }
482    let mut distances = HashMap::new();
483    distances.insert(start.to_string(), 0.0);
484    let mut predecessors = HashMap::new();
485
486    for _ in 0..vertices.len().saturating_sub(1) {
487        let mut updated = false;
488        for e in &edges {
489            if let Some(&du) = distances.get(&e.from) {
490                let dv = distances.get(&e.to).copied().unwrap_or(f64::INFINITY);
491                if du + e.weight < dv {
492                    distances.insert(e.to.clone(), du + e.weight);
493                    predecessors.insert(e.to.clone(), e.from.clone());
494                    updated = true;
495                }
496            }
497        }
498        if !updated {
499            break;
500        }
501    }
502
503    for e in &edges {
504        if let Some(&du) = distances.get(&e.from) {
505            let dv = distances.get(&e.to).copied().unwrap_or(f64::INFINITY);
506            if du + e.weight < dv {
507                return Err(Error::NegativeCycle);
508            }
509        }
510    }
511    Ok((distances, predecessors))
512}
513
514// ---------------- Dynamic programming ----------------
515
516/// 0/1 knapsack.
517pub fn knapsack_01(weights: &[i64], values: &[i64], capacity: i64) -> Result<i64, Error> {
518    if weights.len() != values.len() {
519        return Err(Error::InvalidInput);
520    }
521    if capacity < 0 {
522        return Err(Error::InvalidInput);
523    }
524    let cap = capacity as usize;
525    let mut dp = vec![0; cap + 1];
526    for i in 0..weights.len() {
527        let w = weights[i] as usize;
528        if weights[i] < 0 {
529            return Err(Error::InvalidInput);
530        }
531        let v = values[i];
532        for c in (w..=cap).rev() {
533            if dp[c - w] + v > dp[c] {
534                dp[c] = dp[c - w] + v;
535            }
536        }
537    }
538    Ok(dp[cap])
539}
540
541/// Longest common subsequence length.
542pub fn longest_common_subsequence<T: PartialEq>(a: &[T], b: &[T]) -> usize {
543    let (m, n) = (a.len(), b.len());
544    let mut prev = vec![0; n + 1];
545    for i in 1..=m {
546        let mut curr = vec![0; n + 1];
547        for j in 1..=n {
548            if a[i - 1] == b[j - 1] {
549                curr[j] = prev[j - 1] + 1;
550            } else {
551                curr[j] = prev[j].max(curr[j - 1]);
552            }
553        }
554        prev = curr;
555    }
556    prev[n]
557}
558
559/// Levenshtein distance.
560pub fn edit_distance<T: PartialEq>(a: &[T], b: &[T]) -> usize {
561    let (m, n) = (a.len(), b.len());
562    let mut prev: Vec<usize> = (0..=n).collect();
563    for i in 1..=m {
564        let mut curr = vec![0; n + 1];
565        curr[0] = i;
566        for j in 1..=n {
567            let cost = if a[i - 1] == b[j - 1] { 0 } else { 1 };
568            let insertion = curr[j - 1] + 1;
569            let deletion = prev[j] + 1;
570            let substitution = prev[j - 1] + cost;
571            curr[j] = insertion.min(deletion).min(substitution);
572        }
573        prev = curr;
574    }
575    prev[n]
576}
577
578// ---------------- String algorithms ----------------
579
580/// Knuth-Morris-Pratt pattern matching.
581pub fn kmp_search(text: &str, pattern: &str) -> Result<Vec<usize>, Error> {
582    if pattern.is_empty() {
583        return Err(Error::InvalidInput);
584    }
585    let t = text.as_bytes();
586    let p = pattern.as_bytes();
587    let failure = compute_kmp_failure(p);
588    let mut matches = Vec::new();
589    let mut j = 0;
590    for i in 0..t.len() {
591        while j > 0 && t[i] != p[j] {
592            j = failure[j - 1];
593        }
594        if t[i] == p[j] {
595            j += 1;
596        }
597        if j == p.len() {
598            matches.push(i - p.len() + 1);
599            j = failure[j - 1];
600        }
601    }
602    Ok(matches)
603}
604
605fn compute_kmp_failure(pattern: &[u8]) -> Vec<usize> {
606    let mut failure = vec![0; pattern.len()];
607    let mut j = 0;
608    for i in 1..pattern.len() {
609        while j > 0 && pattern[i] != pattern[j] {
610            j = failure[j - 1];
611        }
612        if pattern[i] == pattern[j] {
613            j += 1;
614            failure[i] = j;
615        }
616    }
617    failure
618}
619
620/// Rolling-hash pattern matching.
621pub fn rabin_karp_search(
622    text: &str,
623    pattern: &str,
624    base: i64,
625    modulus: i64,
626) -> Result<Vec<usize>, Error> {
627    if pattern.is_empty() {
628        return Err(Error::InvalidInput);
629    }
630    let t = text.as_bytes();
631    let p = pattern.as_bytes();
632    let (n, m) = (t.len(), p.len());
633    if m > n {
634        return Ok(Vec::new());
635    }
636    let mut h = 1i64;
637    for _ in 0..m - 1 {
638        h = (h * base) % modulus;
639    }
640    let mut pattern_hash = 0i64;
641    let mut text_hash = 0i64;
642    for i in 0..m {
643        pattern_hash = (pattern_hash * base + p[i] as i64) % modulus;
644        text_hash = (text_hash * base + t[i] as i64) % modulus;
645    }
646    let mut matches = Vec::new();
647    for i in 0..=n - m {
648        if text_hash == pattern_hash && &t[i..i + m] == p {
649            matches.push(i);
650        }
651        if i < n - m {
652            text_hash = (text_hash - t[i] as i64 * h) % modulus;
653            text_hash = (text_hash * base + t[i + m] as i64) % modulus;
654            text_hash = ((text_hash % modulus) + modulus) % modulus;
655        }
656    }
657    Ok(matches)
658}
659
660/// Boyer-Moore pattern matching with the bad-character rule.
661pub fn boyer_moore_search(text: &str, pattern: &str) -> Result<Vec<usize>, Error> {
662    if pattern.is_empty() {
663        return Err(Error::InvalidInput);
664    }
665    let t = text.as_bytes();
666    let p = pattern.as_bytes();
667    let (n, m) = (t.len(), p.len());
668    if m > n {
669        return Ok(Vec::new());
670    }
671    let mut bad_char = HashMap::new();
672    for (i, &b) in p.iter().enumerate() {
673        bad_char.insert(b, i);
674    }
675    let mut matches = Vec::new();
676    let mut i = 0usize;
677    while i <= n - m {
678        let mut j = (m - 1) as isize;
679        while j >= 0 && t[i + j as usize] == p[j as usize] {
680            j -= 1;
681        }
682        if j < 0 {
683            matches.push(i);
684            i += m;
685        } else {
686            let ju = j as usize;
687            let last = bad_char.get(&t[i + ju]).copied().unwrap_or(usize::MAX);
688            let mut shift = if ju > last { ju - last } else { 1 };
689            if shift < 1 {
690                shift = 1;
691            }
692            i += shift;
693        }
694    }
695    Ok(matches)
696}
697
698// ---------------- Greedy ----------------
699
700/// Maximum compatible activity indices.
701pub fn activity_selection(activities: &[(i64, i64)]) -> Result<Vec<usize>, Error> {
702    if activities.is_empty() {
703        return Ok(Vec::new());
704    }
705    #[derive(Clone, Copy)]
706    struct Indexed {
707        index: usize,
708        start: i64,
709        end: i64,
710    }
711    let mut list = Vec::with_capacity(activities.len());
712    for (i, &(start, end)) in activities.iter().enumerate() {
713        if start > end {
714            return Err(Error::InvalidInput);
715        }
716        list.push(Indexed { index: i, start, end });
717    }
718    list.sort_by(|a, b| a.end.cmp(&b.end));
719    let mut selected = vec![list[0].index];
720    let mut last_end = list[0].end;
721    for item in list.iter().skip(1) {
722        if item.start >= last_end {
723            selected.push(item.index);
724            last_end = item.end;
725        }
726    }
727    Ok(selected)
728}
729
730/// Fractional knapsack maximum value.
731pub fn fractional_knapsack(
732    weights: &[f64],
733    values: &[f64],
734    capacity: f64,
735) -> Result<f64, Error> {
736    if weights.len() != values.len() {
737        return Err(Error::InvalidInput);
738    }
739    if capacity < 0.0 {
740        return Err(Error::InvalidInput);
741    }
742    #[derive(Clone, Copy)]
743    struct Item {
744        ratio: f64,
745        weight: f64,
746    }
747    let mut items = Vec::with_capacity(weights.len());
748    for i in 0..weights.len() {
749        if weights[i] > 0.0 {
750            items.push(Item {
751                ratio: values[i] / weights[i],
752                weight: weights[i],
753            });
754        }
755    }
756    items.sort_by(|a, b| {
757        b.ratio
758            .partial_cmp(&a.ratio)
759            .unwrap_or(Ordering::Equal)
760    });
761    let mut total = 0.0;
762    let mut remaining = capacity;
763    for it in items {
764        let take = it.weight.min(remaining);
765        total += take * it.ratio;
766        remaining -= take;
767        if remaining <= 0.0 {
768            break;
769        }
770    }
771    Ok(total)
772}
773
774struct HuffmanNode {
775    freq: i64,
776    char: String,
777    left: Option<Box<HuffmanNode>>,
778    right: Option<Box<HuffmanNode>>,
779}
780
781impl PartialEq for HuffmanNode {
782    fn eq(&self, other: &Self) -> bool {
783        self.freq == other.freq && self.char == other.char
784    }
785}
786
787impl Eq for HuffmanNode {}
788
789impl PartialOrd for HuffmanNode {
790    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
791        Some(self.cmp(other))
792    }
793}
794
795impl Ord for HuffmanNode {
796    fn cmp(&self, other: &Self) -> Ordering {
797        self.freq
798            .cmp(&other.freq)
799            .then_with(|| self.char.cmp(&other.char))
800    }
801}
802
803/// Huffman coding.
804pub fn huffman_coding(frequencies: &HashMap<String, i64>) -> Result<HashMap<String, String>, Error> {
805    if frequencies.is_empty() {
806        return Err(Error::InvalidInput);
807    }
808    let mut pq = BinaryHeap::new();
809    for (ch, &freq) in frequencies {
810        pq.push(Reverse(HuffmanNode {
811            freq,
812            char: ch.clone(),
813            left: None,
814            right: None,
815        }));
816    }
817    if pq.len() == 1 {
818        let node = pq.pop().unwrap().0;
819        let mut codes = HashMap::new();
820        codes.insert(node.char, "0".to_string());
821        return Ok(codes);
822    }
823    while pq.len() > 1 {
824        let left = pq.pop().unwrap().0;
825        let right = pq.pop().unwrap().0;
826        let parent = HuffmanNode {
827            freq: left.freq + right.freq,
828            char: String::new(),
829            left: Some(Box::new(left)),
830            right: Some(Box::new(right)),
831        };
832        pq.push(Reverse(parent));
833    }
834    let root = pq.pop().unwrap().0;
835    let mut codes = HashMap::new();
836    assign_huffman_codes(&root, "", &mut codes);
837    Ok(codes)
838}
839
840fn assign_huffman_codes(node: &HuffmanNode, prefix: &str, codes: &mut HashMap<String, String>) {
841    if !node.char.is_empty() {
842        if prefix.is_empty() {
843            codes.insert(node.char.clone(), "0".to_string());
844        } else {
845            codes.insert(node.char.clone(), prefix.to_string());
846        }
847        return;
848    }
849    if let Some(ref left) = node.left {
850        assign_huffman_codes(left, &format!("{}0", prefix), codes);
851    }
852    if let Some(ref right) = node.right {
853        assign_huffman_codes(right, &format!("{}1", prefix), codes);
854    }
855}
856
857// ---------------- Divide and conquer ----------------
858
859/// Maximum subarray sum.
860pub fn max_subarray(arr: &[i64]) -> Result<i64, Error> {
861    if arr.is_empty() {
862        return Err(Error::InvalidInput);
863    }
864    Ok(max_subarray_dc(arr, 0, arr.len() - 1))
865}
866
867fn max_subarray_dc(arr: &[i64], left: usize, right: usize) -> i64 {
868    if left == right {
869        return arr[left];
870    }
871    let mid = (left + right) / 2;
872    let left_sum = max_subarray_dc(arr, left, mid);
873    let right_sum = max_subarray_dc(arr, mid + 1, right);
874    let cross_sum = max_crossing_sum(arr, left, mid, right);
875    left_sum.max(right_sum).max(cross_sum)
876}
877
878fn max_crossing_sum(arr: &[i64], left: usize, mid: usize, right: usize) -> i64 {
879    let mut sum = arr[mid];
880    let mut left_max = arr[mid];
881    for i in (left..mid).rev() {
882        sum += arr[i];
883        if sum > left_max {
884            left_max = sum;
885        }
886    }
887    sum = arr[mid + 1];
888    let mut right_max = arr[mid + 1];
889    for i in mid + 2..=right {
890        sum += arr[i];
891        if sum > right_max {
892            right_max = sum;
893        }
894    }
895    left_max + right_max
896}
897
898/// Inversion count.
899pub fn count_inversions<T: Ord + Clone>(arr: &[T]) -> usize {
900    let (_, count) = sort_and_count(arr);
901    count
902}
903
904fn sort_and_count<T: Ord + Clone>(arr: &[T]) -> (Vec<T>, usize) {
905    let n = arr.len();
906    if n <= 1 {
907        return (arr.to_vec(), 0);
908    }
909    let mid = n / 2;
910    let (left, lcount) = sort_and_count(&arr[..mid]);
911    let (right, rcount) = sort_and_count(&arr[mid..]);
912    let (merged, scount) = merge_and_count(&left, &right);
913    (merged, lcount + rcount + scount)
914}
915
916fn merge_and_count<T: Ord + Clone>(left: &[T], right: &[T]) -> (Vec<T>, usize) {
917    let mut merged = Vec::with_capacity(left.len() + right.len());
918    let mut count = 0;
919    let mut i = 0;
920    let mut j = 0;
921    while i < left.len() && j < right.len() {
922        if left[i] <= right[j] {
923            merged.push(left[i].clone());
924            i += 1;
925        } else {
926            merged.push(right[j].clone());
927            j += 1;
928            count += left.len() - i;
929        }
930    }
931    merged.extend_from_slice(&left[i..]);
932    merged.extend_from_slice(&right[j..]);
933    (merged, count)
934}
935
936/// Exponentiation by squaring.
937pub fn fast_power(base: f64, exponent: i64) -> f64 {
938    if exponent < 0 {
939        return 1.0 / fast_power(base, -exponent);
940    }
941    if exponent == 0 {
942        return 1.0;
943    }
944    if exponent == 1 {
945        return base;
946    }
947    let half = fast_power(base, exponent / 2);
948    if exponent % 2 == 0 {
949        half * half
950    } else {
951        base * half * half
952    }
953}