Skip to content

Commit 9fc3fb2

Browse files
committed
LC 2106. Maximum Fruits Harvested After at Most K Steps
1 parent 15c13b8 commit 9fc3fb2

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ to the solution in this repository.
669669
| [2092. Find All People With Secret][lc2092] | 🔴 Hard | [![rust](res/rs.png)][lc2092rs] |
670670
| [2095. Delete the Middle Node of a Linked List][lc2095] | 🟠 Medium | [![python](res/py.png)][lc2095py] |
671671
| [2101. Detonate the Maximum Bombs][lc2101] | 🟠 Medium | [![rust](res/rs.png)][lc2101rs] |
672+
| [2106. Maximum Fruits Harvested After at Most K Steps][lc2106] | 🔴 Hard | [![rust](res/rs.png)][lc2106rs] |
672673
| [2108. Find First Palindromic String in the Array][lc2108] | 🟢 Easy | [![rust](res/rs.png)][lc2108rs] |
673674
| [2115. Find All Possible Recipes from Given Supplies][lc2115] | 🟠 Medium | [![python](res/py.png)][lc2115py] |
674675
| [2125. Number of Laser Beams in a Bank][lc2125] | 🟠 Medium | [![rust](res/rs.png)][lc2125rs] |
@@ -2274,6 +2275,8 @@ to the solution in this repository.
22742275
[lc2095py]: leetcode/delete-the-middle-node-of-a-linked-list.py
22752276
[lc2101]: https://leetcode.com/problems/detonate-the-maximum-bombs/
22762277
[lc2101rs]: leetcode/detonate-the-maximum-bombs.rs
2278+
[lc2106]: https://leetcode.com/problems/maximum-fruits-harvested-after-at-most-k-steps/
2279+
[lc2106rs]: leetcode/maximum-fruits-harvested-after-at-most-k-steps.rs
22772280
[lc2108]: https://leetcode.com/problems/find-first-palindromic-string-in-the-array/
22782281
[lc2108rs]: leetcode/find-first-palindromic-string-in-the-array.rs
22792282
[lc2115]: https://leetcode.com/problems/find-all-possible-recipes-from-given-supplies/
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// 2106. Maximum Fruits Harvested After at Most K Steps
2+
// 🔴 Hard
3+
//
4+
// https://leetcode.com/problems/maximum-fruits-harvested-after-at-most-k-steps/
5+
//
6+
// Tags: Array - Binary Search - Sliding Window - Prefix Sum
7+
8+
struct Solution;
9+
impl Solution {
10+
/// We can precompute the prefix sums of going left and right, then use a sliding window to
11+
/// check the gains of taking x steps to the left and the available ones to the right and
12+
/// viceversa.
13+
///
14+
/// Time complexity: O(n) - All the operations run in linear time.
15+
/// Space complexity: O(n) - The prefix sum vectors will have at most size n.
16+
///
17+
/// Runtime 6 ms Beats 100%
18+
/// Memory 9.74 MB Beats 100%
19+
pub fn max_total_fruits(fruits: Vec<Vec<i32>>, start_pos: i32, k: i32) -> i32 {
20+
let n = fruits.len();
21+
let insert_index = match fruits.binary_search_by(|v| v[0].cmp(&start_pos)) {
22+
Ok(idx) => idx,
23+
Err(idx) => idx,
24+
};
25+
let mut prefix_sum_left = Vec::with_capacity(insert_index + 1);
26+
let mut total = 0;
27+
for i in 0..=insert_index {
28+
let fi = insert_index - i;
29+
if fi == n || fruits[fi][0] > start_pos {
30+
continue;
31+
}
32+
total += fruits[fi][1];
33+
let steps = start_pos - fruits[fi][0];
34+
if steps > k {
35+
break;
36+
}
37+
prefix_sum_left.push((steps, total));
38+
}
39+
let mut prefix_sum_right = Vec::with_capacity(n - insert_index);
40+
total = 0;
41+
for i in insert_index..n {
42+
total += fruits[i][1];
43+
let steps = fruits[i][0] - start_pos;
44+
if steps > k {
45+
break;
46+
}
47+
prefix_sum_right.push((steps, total));
48+
}
49+
// Account for double counting the fruit at the start position.
50+
let penalty = if insert_index < n && fruits[insert_index][0] == start_pos {
51+
fruits[insert_index][1]
52+
} else {
53+
0
54+
};
55+
let mut res = 0;
56+
// Check the options starting going left.
57+
let mut r = prefix_sum_right.len();
58+
if r > 0 {
59+
r -= 1;
60+
}
61+
for &(steps, gain) in prefix_sum_left.iter() {
62+
let steps_right = k - 2 * steps;
63+
while r > 0 && prefix_sum_right[r].0 > steps_right {
64+
r -= 1;
65+
}
66+
total = gain;
67+
if prefix_sum_right.len() > 0 && prefix_sum_right[r].0 <= steps_right {
68+
total += prefix_sum_right[r].1;
69+
}
70+
res = res.max(total - penalty);
71+
}
72+
// Check the options going right.
73+
let mut l = prefix_sum_left.len();
74+
if l > 0 {
75+
l -= 1;
76+
}
77+
for &(steps, gain) in prefix_sum_right.iter() {
78+
let steps_left = k - 2 * steps;
79+
while l > 0 && prefix_sum_left[l].0 > steps_left {
80+
l -= 1;
81+
}
82+
total = gain;
83+
if prefix_sum_left.len() > 0 && prefix_sum_left[l].0 <= steps_left {
84+
total += prefix_sum_left[l].1;
85+
}
86+
res = res.max(total - penalty);
87+
}
88+
res
89+
}
90+
}
91+
92+
// Tests.
93+
fn main() {
94+
let tests = [
95+
(vec![[2, 8], [6, 3], [8, 6]], 5, 4, 9),
96+
(
97+
vec![[0, 9], [4, 1], [5, 7], [6, 2], [7, 4], [10, 9]],
98+
5,
99+
4,
100+
14,
101+
),
102+
(vec![[0, 3], [6, 4], [8, 5]], 3, 2, 0),
103+
(vec![[200000, 10000]], 0, 200000, 10000),
104+
(vec![[0, 10000]], 200000, 200000, 10000),
105+
];
106+
println!("\n\x1b[92m» Running {} tests...\x1b[0m", tests.len());
107+
let mut success = 0;
108+
for (i, t) in tests.iter().enumerate() {
109+
let res = Solution::max_total_fruits(t.0.iter().map(|a| a.to_vec()).collect(), t.1, t.2);
110+
if res == t.3 {
111+
success += 1;
112+
println!("\x1b[92m✔\x1b[95m Test {} passed!\x1b[0m", i);
113+
} else {
114+
println!(
115+
"\x1b[31mx\x1b[95m Test {} failed expected: {:?} but got {}!!\x1b[0m",
116+
i, t.3, res
117+
);
118+
}
119+
}
120+
println!();
121+
if success == tests.len() {
122+
println!("\x1b[30;42m✔ All tests passed!\x1b[0m")
123+
} else if success == 0 {
124+
println!("\x1b[31mx \x1b[41;37mAll tests failed!\x1b[0m")
125+
} else {
126+
println!(
127+
"\x1b[31mx\x1b[95m {} tests failed!\x1b[0m",
128+
tests.len() - success
129+
)
130+
}
131+
}

0 commit comments

Comments
 (0)