Skip to content

Commit fb98dc4

Browse files
Optimize Fruits Into Baskets III with TreeSet/sorted arrays to fix TLE
1 parent 07b3d45 commit fb98dc4

File tree

4 files changed

+47
-42
lines changed

4 files changed

+47
-42
lines changed

Medium/2025-08-06-3478-FruitsIntoBasketsIII/explanation.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@ Since we can skip one fruit and place the rest, we return 0.
4646
- We find the best outcome among all possible skip combinations
4747

4848
## Complexity Analysis
49-
- **Time Complexity**: O(n²) - For each skip possibility, we do O(n²) work
50-
- **Space Complexity**: O(n) - To track which baskets are used
49+
- **Time Complexity**: O(n log n) - Sort baskets once, then O(n) for each skip possibility
50+
- **Space Complexity**: O(n) - To maintain sorted list of available baskets
5151

5252
## Key Insights
5353
- This is an extension of the previous problem with skip logic
5454
- We need to try all possible skip combinations to find the optimal solution
55-
- The greedy placement strategy remains the same for each attempt
55+
- Using sorted data structures (TreeSet/Array) for efficient basket matching
56+
- Greedy placement strategy with optimized basket selection
5657

5758
## Alternative Approaches
5859
1. **Brute Force**: Try all possible skip combinations - O(n!) time

Medium/2025-08-06-3478-FruitsIntoBasketsIII/solution.java

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1+
import java.util.*;
2+
13
class Solution {
24
public int numOfUnplacedFruits(int[] fruits, int[] baskets) {
35
int minUnplaced = Integer.MAX_VALUE;
46

57
// Try placing all fruits without skipping
6-
minUnplaced = Math.min(minUnplaced, placeFruits(fruits, baskets, -1));
8+
minUnplaced = Math.min(minUnplaced, placeFruitsOptimized(fruits, baskets, -1));
79

810
// Try skipping each fruit type
911
for (int skipIndex = 0; skipIndex < fruits.length; skipIndex++) {
10-
minUnplaced = Math.min(minUnplaced, placeFruits(fruits, baskets, skipIndex));
12+
minUnplaced = Math.min(minUnplaced, placeFruitsOptimized(fruits, baskets, skipIndex));
1113
}
1214

1315
return minUnplaced;
1416
}
1517

16-
private int placeFruits(int[] fruits, int[] baskets, int skipIndex) {
17-
boolean[] used = new boolean[baskets.length];
18+
private int placeFruitsOptimized(int[] fruits, int[] baskets, int skipIndex) {
19+
// Use TreeSet to maintain available baskets efficiently
20+
TreeSet<Integer> availableBaskets = new TreeSet<>();
21+
for (int basket : baskets) {
22+
availableBaskets.add(basket);
23+
}
24+
1825
int unplaced = 0;
1926

2027
for (int i = 0; i < fruits.length; i++) {
@@ -23,19 +30,13 @@ private int placeFruits(int[] fruits, int[] baskets, int skipIndex) {
2330
continue;
2431
}
2532

26-
boolean placed = false;
27-
28-
// Find the leftmost available basket with sufficient capacity
29-
for (int j = 0; j < baskets.length; j++) {
30-
if (!used[j] && baskets[j] >= fruits[i]) {
31-
used[j] = true; // Mark basket as used
32-
placed = true;
33-
break;
34-
}
35-
}
33+
// Find the smallest available basket that can hold this fruit
34+
Integer basket = availableBaskets.ceiling(fruits[i]);
3635

37-
if (!placed) {
36+
if (basket == null) {
3837
unplaced++;
38+
} else {
39+
availableBaskets.remove(basket);
3940
}
4041
}
4142

Medium/2025-08-06-3478-FruitsIntoBasketsIII/solution.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ var numOfUnplacedFruits = function(fruits, baskets) {
77
let minUnplaced = Infinity;
88

99
// Try placing all fruits without skipping
10-
minUnplaced = Math.min(minUnplaced, placeFruits(fruits, baskets, -1));
10+
minUnplaced = Math.min(minUnplaced, placeFruitsOptimized(fruits, baskets, -1));
1111

1212
// Try skipping each fruit type
1313
for (let skipIndex = 0; skipIndex < fruits.length; skipIndex++) {
14-
minUnplaced = Math.min(minUnplaced, placeFruits(fruits, baskets, skipIndex));
14+
minUnplaced = Math.min(minUnplaced, placeFruitsOptimized(fruits, baskets, skipIndex));
1515
}
1616

1717
return minUnplaced;
1818
};
1919

20-
function placeFruits(fruits, baskets, skipIndex) {
21-
const used = new Array(baskets.length).fill(false);
20+
function placeFruitsOptimized(fruits, baskets, skipIndex) {
21+
// Use sorted array to maintain available baskets efficiently
22+
const availableBaskets = [...baskets].sort((a, b) => a - b);
2223
let unplaced = 0;
2324

2425
for (let i = 0; i < fruits.length; i++) {
@@ -27,19 +28,19 @@ function placeFruits(fruits, baskets, skipIndex) {
2728
continue;
2829
}
2930

30-
let placed = false;
31-
32-
// Find the leftmost available basket with sufficient capacity
33-
for (let j = 0; j < baskets.length; j++) {
34-
if (!used[j] && baskets[j] >= fruits[i]) {
35-
used[j] = true; // Mark basket as used
36-
placed = true;
31+
// Find the smallest available basket that can hold this fruit
32+
let basketIndex = -1;
33+
for (let j = 0; j < availableBaskets.length; j++) {
34+
if (availableBaskets[j] >= fruits[i]) {
35+
basketIndex = j;
3736
break;
3837
}
3938
}
4039

41-
if (!placed) {
40+
if (basketIndex === -1) {
4241
unplaced++;
42+
} else {
43+
availableBaskets.splice(basketIndex, 1); // Remove used basket
4344
}
4445
}
4546

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
11
from typing import List
2+
import bisect
23

34
class Solution:
45
def numOfUnplacedFruits(self, fruits: List[int], baskets: List[int]) -> int:
56
min_unplaced = float('inf')
67

78
# Try placing all fruits without skipping
8-
min_unplaced = min(min_unplaced, self.place_fruits(fruits, baskets, -1))
9+
min_unplaced = min(min_unplaced, self.place_fruits_optimized(fruits, baskets, -1))
910

1011
# Try skipping each fruit type
1112
for skip_index in range(len(fruits)):
12-
min_unplaced = min(min_unplaced, self.place_fruits(fruits, baskets, skip_index))
13+
min_unplaced = min(min_unplaced, self.place_fruits_optimized(fruits, baskets, skip_index))
1314

1415
return min_unplaced
1516

16-
def place_fruits(self, fruits: List[int], baskets: List[int], skip_index: int) -> int:
17-
used = [False] * len(baskets)
17+
def place_fruits_optimized(self, fruits: List[int], baskets: List[int], skip_index: int) -> int:
18+
# Use sorted list to maintain available baskets efficiently
19+
available_baskets = sorted(baskets)
1820
unplaced = 0
1921

2022
for i in range(len(fruits)):
2123
if i == skip_index:
2224
unplaced += 1 # Count skipped fruit as unplaced
2325
continue
2426

25-
placed = False
26-
27-
# Find the leftmost available basket with sufficient capacity
28-
for j in range(len(baskets)):
29-
if not used[j] and baskets[j] >= fruits[i]:
30-
used[j] = True # Mark basket as used
31-
placed = True
27+
# Find the smallest available basket that can hold this fruit
28+
basket_index = -1
29+
for j in range(len(available_baskets)):
30+
if available_baskets[j] >= fruits[i]:
31+
basket_index = j
3232
break
3333

34-
if not placed:
34+
if basket_index == -1:
3535
unplaced += 1
36+
else:
37+
available_baskets.pop(basket_index) # Remove used basket
3638

3739
return unplaced

0 commit comments

Comments
 (0)