Fractional Knapsack Problem in DSA Rust - Time & Space Complexity
We want to understand how the time needed to solve the fractional knapsack problem changes as the number of items grows.
Specifically, how does sorting and selecting items affect the total work done?
Analyze the time complexity of the following code snippet.
fn fractional_knapsack(weights: &[f64], values: &[f64], capacity: f64) -> f64 {
let n = weights.len();
let mut items: Vec<(f64, f64)> = weights.iter()
.zip(values.iter())
.map(|(&w, &v)| (v / w, w))
.collect();
items.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
let mut total_value = 0.0;
let mut remaining = capacity;
for &(ratio, weight) in &items {
if remaining == 0.0 { break; }
let take = remaining.min(weight);
total_value += take * ratio;
remaining -= take;
}
total_value
}
This code sorts items by value per weight and then takes as much as possible from the best items until capacity is full.
- Primary operation: Sorting the list of items by their value-to-weight ratio.
- How many times: Sorting runs once over all items (n items).
- Secondary operation: Single loop over all items to pick fractions.
- How many times: Loop runs at most n times.
Sorting takes more time as the number of items grows, roughly n log n steps.
The loop to pick items grows linearly with n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * log(10) + 10 ≈ 43 steps |
| 100 | About 100 * log(100) + 100 ≈ 700 steps |
| 1000 | About 1000 * log(1000) + 1000 ≈ 10,000 steps |
Pattern observation: The sorting dominates and grows faster than the simple loop, so total work grows a bit faster than just doubling input size.
Time Complexity: O(n log n)
This means as the number of items grows, the time needed grows a bit faster than just multiplying by n, mainly due to sorting.
[X] Wrong: "The loop to pick items is the slowest part, so the complexity is O(n)."
[OK] Correct: Sorting the items by ratio takes more time than the loop, so it controls the overall speed.
Understanding how sorting affects the fractional knapsack problem helps you explain your approach clearly and shows you know where the main work happens.
"What if the items were already sorted by value-to-weight ratio? How would the time complexity change?"
Practice
Fractional Knapsack Problem?Solution
Step 1: Understand problem objective
The fractional knapsack problem aims to maximize the total value of items placed in a knapsack without exceeding its weight capacity.Step 2: Recognize fractional selection
Unlike the 0/1 knapsack, it allows taking fractions of items to fill the knapsack optimally.Final Answer:
Maximize total value by taking fractions of items within weight limit -> Option AQuick Check:
Goal = maximize value with fractions [OK]
- Thinking only whole items can be taken
- Confusing with minimizing weight
- Ignoring value-to-weight ratio
Solution
Step 1: Identify correct struct syntax
Rust structs use curly braces with field names and types, e.g.,struct Item { weight: f64, value: f64 }.Step 2: Check field types for fractional knapsack
Weights and values can be fractional, sof64(floating-point) is appropriate.Final Answer:
struct Item { weight: f64, value: f64 } -> Option BQuick Check:
Correct struct syntax with f64 fields [OK]
- Using tuple struct syntax incorrectly
- Using integer or wrong types for fractional values
- Using incompatible types like String or bool
struct Item { weight: f64, value: f64 }
fn fractional_knapsack(items: &mut Vec<Item>, capacity: f64) -> f64 {
items.sort_by(|a, b| (b.value / b.weight).partial_cmp(&(a.value / a.weight)).unwrap());
let mut total_value = 0.0;
let mut remaining = capacity;
for item in items.iter() {
if item.weight <= remaining {
total_value += item.value;
remaining -= item.weight;
} else {
total_value += item.value * (remaining / item.weight);
break;
}
}
total_value
}
fn main() {
let mut items = vec![
Item { weight: 10.0, value: 60.0 },
Item { weight: 20.0, value: 100.0 },
Item { weight: 30.0, value: 120.0 },
];
let capacity = 50.0;
let max_value = fractional_knapsack(&mut items, capacity);
println!("{:.2}", max_value);
}Solution
Step 1: Sort items by value/weight ratio descending
Ratios: 60/10=6, 100/20=5, 120/30=4. Sorted order: Item1, Item2, Item3.Step 2: Add items until capacity 50
Add Item1 fully (weight 10, value 60), remaining 40.
Add Item2 fully (weight 20, value 100), remaining 20.
Add fraction of Item3: fraction = 20/30 = 2/3, value = 120 * 2/3 = 80.
Total value = 60 + 100 + 80 = 240.Final Answer:
240.00 -> Option DQuick Check:
Sum values with fractions = 240.00 [OK]
- Not sorting items by ratio
- Taking whole items only
- Incorrect fraction calculation
fn fractional_knapsack(items: &mut Vec<Item>, capacity: f64) -> f64 {
items.sort_by(|a, b| (a.value / a.weight).partial_cmp(&(b.value / b.weight)).unwrap());
let mut total_value = 0.0;
let mut remaining = capacity;
for item in items.iter() {
if item.weight <= remaining {
total_value += item.value;
remaining -= item.weight;
} else {
total_value += item.value * (remaining / item.weight);
break;
}
}
total_value
}Solution
Step 1: Check sorting comparator
The code sorts by (a.value / a.weight).partial_cmp(&(b.value / b.weight)), which sorts ascending by ratio.Step 2: Correct sorting order for greedy approach
Fractional knapsack requires descending order by value/weight ratio to pick highest value items first.Final Answer:
Sorting order is ascending, should be descending by value/weight -> Option AQuick Check:
Sort descending by ratio for max value [OK]
- Sorting ascending instead of descending
- Confusing iter() and into_iter() ownership
- Miscomputing fractional value
[(5, 30), (10, 40), (15, 45)] and knapsack capacity 20, what is the maximum value using fractional knapsack?Solution
Step 1: Calculate value/weight ratios and sort descending
Ratios: 30/5=6, 40/10=4, 45/15=3.
Sorted order: (5,30), (10,40), (15,45).Step 2: Fill knapsack capacity 20 greedily
Take full (5,30), remaining 15, total value 30.
Take full (10,40), remaining 5, total value 70.
Take fraction of (15,45): fraction = 5/15 = 1/3, value = 45 * 1/3 = 15.
Total value = 70 + 15 = 85.Step 3: Verify options
85 is 85, matching calculation.Final Answer:
85 -> Option CQuick Check:
Greedy fill with fractions = 85 [OK]
- Not sorting by ratio
- Taking items in wrong order
- Incorrect fraction calculation
Ready to prove it?
Pass the test and this pattern moves unknown
