We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Collections, Text and First Iterators step 13 of 21
BinaryHeap is a max-heap, and Reverse is the fix
Implement two priority-queue operations:
pub fn k_smallest(nums: Vec<i64>, k: usize) -> Vec<i64>
pub fn merge_sorted(lists: Vec<Vec<i64>>) -> Vec<i64>
k_smallest returns the smallest min(k, nums.len()) values in ascending
order. Count duplicates separately. Return an empty vector for zero k or
empty input. A large k does not require storage for nonexistent elements.
merge_sorted combines lists that are individually in nondecreasing order.
Return every value, including duplicates, in nondecreasing order. Empty
inner lists and an empty outer list are valid. Inputs and the resulting
output fit in memory.
The starter compiles and passes Clippy, but chooses the wrong heap ordering. Fix both functions; the grader calls both through its supplied harness.
Choose which value should come out first
BinaryHeap<T> returns the greatest value according to T's ordering.
Wrapping values in Reverse reverses that ordering, making the smallest
original value come out first:
use std::cmp::Reverse;
use std::collections::BinaryHeap;
fn main() {
let mut largest_first = BinaryHeap::from([3, 9, 1]);
assert_eq!(largest_first.pop(), Some(9));
let mut smallest_first = BinaryHeap::from([Reverse(3), Reverse(9), Reverse(1)]);
assert_eq!(smallest_first.pop(), Some(Reverse(1)));
}
Reverse<T> is a
transparent wrapper around T. It changes comparison behavior without
adding a heap allocation of its own. This does not make every heap
operation free: comparisons, moving elements and growing storage still
have costs.
Unwrap a popped value with a pattern such as Some(Reverse(value)).
Negating integers is not an equivalent general solution: negating
i64::MIN cannot produce a representable positive i64.
Keep the smallest values in a bounded max-heap
For k_smallest, a max-heap is useful because its root is the largest
candidate you currently hold. That is the candidate to discard when a
smaller value arrives.
Set the effective limit to min(k, nums.len()), and return early if it is
zero. Push each input value. Whenever the heap exceeds that limit, pop its
largest value. After each iteration, it contains the smallest values seen
so far, up to the limit. Finish by returning those values in sorted order.
For [5, 1, 4, 2, 3] and k = 2, the final candidates are 1 and 2.
Their order inside the heap is not the required output order.
Do not reserve k + 1 elements directly. k can be much larger than the
input length, and adding one can overflow. The reference starts with an
empty heap and lets it grow with the candidates actually encountered.
Let n be the input length and m = min(k, n). For positive m, the
push-then-evict method takes O(n log(m + 1)) time in the worst case; sorting
the retained values adds O(m log(m + 1)). Its heap storage is O(m), with
room for one temporary extra candidate. This is additional storage: the
function already receives an allocated input vector.
Sorting the owned input is also a valid way to meet the output contract.
A bounded heap is especially useful when retaining only a small fraction
of the input or adapting the algorithm to a stream. Which approach is
faster depends on the workload; k == n does not imply a universal timing
result.
Heap iteration is not sorted output
into_sorted_vec() returns ascending order according to the heap's element
type. into_vec() returns its storage without sorting it. Iteration also
does not promise sorted order. It is fine to iterate for an order-independent
calculation or diagnostic display; do not treat that sequence as sorted.
use std::cmp::Reverse;
use std::collections::BinaryHeap;
fn main() {
let heap = BinaryHeap::from([5, 1, 8, 3]);
assert_eq!(heap.peek(), Some(&8));
assert_eq!(heap.into_sorted_vec(), vec![1, 3, 5, 8]);
let reversed = BinaryHeap::from([Reverse(1), Reverse(3), Reverse(2)]);
let values: Vec<_> = reversed.into_sorted_vec().into_iter()
.map(|Reverse(value)| value).collect();
assert_eq!(values, vec![3, 2, 1]);
}
Notice the final result: sorting Reverse values in their ascending order
gives descending order for the original numbers. Repeatedly popping that
same min-heap would instead yield the original numbers in ascending order.
Merge using one candidate per list
For merge_sorted, put the first value of each nonempty list into a
min-heap. Store Reverse((value, list_index, position)) so each entry also
identifies where to find its successor.
Repeatedly pop the smallest candidate, append its value to the output, and insert the next value from the same list if one exists. Because each input list is sorted, no unseen value in that list belongs before its current candidate.
Tuples compare lexicographically. The value is the primary key; list index and position break ties. This keeps duplicate values while making candidate selection well-defined. The output contains values only, so their source identity is not part of the result.
With r input lists, q nonempty lists and N total values, this approach
takes O(r + N log(q + 1)) time and O(q) candidate storage. The output needs
O(N) space, and this function also retains the provided input lists during
the merge.
Keep custom ordering consistent
If you implement ordering for your own type, Ord, PartialOrd and equality
must agree. In particular, partial_cmp(a, b) must return
Some(a.cmp(b)). Deriving one comparison trait while manually implementing
the other can make them inconsistent; Clippy catches that pattern, but
cannot prove every custom ordering correct.
Violating ordering requirements is a logic error with unspecified behavior,
not a promise of one particular wrong result. Do not change an element's
relative ordering through interior mutability while it is in a heap.
See the BinaryHeap contract
and Ord requirements.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.