Skip to content

Commit 15c13b8

Browse files
committed
LC 2561. Rearranging Fruits
1 parent 86007e4 commit 15c13b8

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ to the solution in this repository.
740740
| [2540. Minimum Common Value][lc2540] | 🟢 Easy | [![rust](res/rs.png)][lc2540rs] |
741741
| [2542. Maximum Subsequence Score][lc2542] | 🟠 Medium | [![rust](res/rs.png)][lc2542rs] |
742742
| [2543. Check if Point Is Reachable][lc2543] | 🔴 Hard | [![python](res/py.png)][lc2543py] [![rust](res/rs.png)][lc2543rs] |
743+
| [2561. Rearranging Fruits][lc2561] | 🔴 Hard | [![rust](res/rs.png)][lc2561rs] |
743744
| [2563. Count the Number of Fair Pairs][lc2563] | 🟠 Medium | [![rust](res/rs.png)][lc2563rs] |
744745
| [2583. Kth Largest Sum in a Binary Tree][lc2583] | 🟠 Medium | [![rust](res/rs.png)][lc2583rs] |
745746
| [2585. Number of Ways to Earn Points][lc2585] | 🔴 Hard | [![python](res/py.png)][lc2585py] [![rust](res/rs.png)][lc2585rs] |
@@ -2433,6 +2434,8 @@ to the solution in this repository.
24332434
[lc2543]: https://leetcode.com/problems/check-if-point-is-reachable/
24342435
[lc2543py]: leetcode/check-if-point-is-reachable.py
24352436
[lc2543rs]: leetcode/check-if-point-is-reachable.rs
2437+
[lc2561]: https://leetcode.com/problems/rearranging-fruits/
2438+
[lc2561rs]: leetcode/rearranging-fruits.rs
24362439
[lc2563]: https://leetcode.com/problems/count-the-number-of-fair-pairs/
24372440
[lc2563rs]: leetcode.com/count-the-number-of-fair-pairs.rs
24382441
[lc2583]: https://leetcode.com/problems/kth-largest-sum-in-a-binary-tree/

leetcode/rearranging-fruits.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// 2561. Rearranging Fruits
2+
// 🔴 Hard
3+
//
4+
// https://leetcode.com/problems/rearranging-fruits/
5+
//
6+
// Tags: Array - Hash Table - Greedy - Sort
7+
8+
use std::collections::{HashMap, HashSet};
9+
10+
struct Solution;
11+
impl Solution {
12+
/// Get the counts of elements in both vectors, then iterate over all the values found in both
13+
/// vectors, for each check if the count is uneven, equal or even, if even but not equal, we
14+
/// will need to swap some elements from one vector to the other, save these to_swap elements.
15+
/// Once we have all elements that need to be swapped, for each element, check if swapping them
16+
/// directly is more efficient than doing two indirect swaps using the minimum value in both
17+
/// vectors and add the minimum between these two to the result.
18+
///
19+
/// Time complexity: O(n*log(n)) - Sorting the to_swap vectors in the worst case.
20+
/// Space complexity: O(n) - The hashmaps, the all_keys vector and the swap vectors.
21+
///
22+
/// Runtime 26 ms Beats 20%
23+
/// Memory 7.62 MB Beats 20%
24+
pub fn min_cost(basket1: Vec<i32>, basket2: Vec<i32>) -> i64 {
25+
let n = basket1.len();
26+
let mut min = basket1[0];
27+
let mut counts1: HashMap<i32, usize> = HashMap::new();
28+
for &num in basket1.iter() {
29+
*counts1.entry(num).or_default() += 1;
30+
}
31+
let mut counts2: HashMap<i32, usize> = HashMap::new();
32+
for &num in basket2.iter() {
33+
*counts2.entry(num).or_default() += 1;
34+
}
35+
let all_keys: HashSet<_> = basket1.into_iter().chain(basket2).collect();
36+
let mut atob = Vec::with_capacity(n);
37+
let mut btoa = Vec::with_capacity(n);
38+
for key in all_keys.iter() {
39+
if *key < min {
40+
min = *key;
41+
}
42+
let mut c1 = *counts1.get(key).unwrap_or(&0);
43+
let mut c2 = *counts2.get(key).unwrap_or(&0);
44+
// println!("{key}: {c1} {c2}");
45+
if (c1 + c2) % 2 != 0 {
46+
return -1;
47+
}
48+
while c1 != c2 {
49+
if c1 > c2 {
50+
atob.push(*key);
51+
c1 -= 1;
52+
c2 += 1;
53+
} else {
54+
btoa.push(*key);
55+
c2 -= 1;
56+
c1 += 1;
57+
}
58+
}
59+
// println!("{:?} {:?}", atob, btoa);
60+
}
61+
atob.sort_unstable();
62+
btoa.sort_unstable();
63+
// println!("{:?} {:?}", atob, btoa);
64+
min *= 2;
65+
if atob.len() != btoa.len() {
66+
panic!("Move vectors of different size");
67+
}
68+
let (mut a, mut b, l, mut res) = (0, 0, atob.len(), 0i64);
69+
while a + b < l {
70+
if atob.get(a).unwrap_or(&i32::MAX) < btoa.get(b).unwrap_or(&i32::MAX) {
71+
res += (atob[a].min(min)) as i64;
72+
a += 1;
73+
} else {
74+
res += (btoa[b].min(min)) as i64;
75+
b += 1;
76+
}
77+
}
78+
res
79+
}
80+
}
81+
82+
// Tests.
83+
fn main() {
84+
let tests = [
85+
(vec![4, 2, 2, 2], vec![1, 4, 1, 2], 1),
86+
(vec![2, 3, 4, 1], vec![3, 2, 5, 1], -1),
87+
(
88+
vec![84, 80, 43, 8, 80, 88, 43, 14, 100, 88],
89+
vec![32, 32, 42, 68, 68, 100, 42, 84, 14, 8],
90+
48,
91+
),
92+
];
93+
println!("\n\x1b[92m» Running {} tests...\x1b[0m", tests.len());
94+
let mut success = 0;
95+
for (i, t) in tests.iter().enumerate() {
96+
let res = Solution::min_cost(t.0.clone(), t.1.clone());
97+
if res == t.2 {
98+
success += 1;
99+
println!("\x1b[92m✔\x1b[95m Test {} passed!\x1b[0m", i);
100+
} else {
101+
println!(
102+
"\x1b[31mx\x1b[95m Test {} failed expected: {:?} but got {}!!\x1b[0m",
103+
i, t.2, res
104+
);
105+
}
106+
}
107+
println!();
108+
if success == tests.len() {
109+
println!("\x1b[30;42m✔ All tests passed!\x1b[0m")
110+
} else if success == 0 {
111+
println!("\x1b[31mx \x1b[41;37mAll tests failed!\x1b[0m")
112+
} else {
113+
println!(
114+
"\x1b[31mx\x1b[95m {} tests failed!\x1b[0m",
115+
tests.len() - success
116+
)
117+
}
118+
}

0 commit comments

Comments
 (0)