-
-
Save akolybelnikov/53818257f13247a83939b799e3fd431f to your computer and use it in GitHub Desktop.
Решение задачи №138 от UniLecs (Максимальная последовательность по модулю)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate itertools; | |
use itertools::{Itertools, Either::*}; | |
// Самый первый вариант — разбиваем массив | |
// на вектор отрицательных чисел и вектор положительных, | |
// а затем возвращаем тот, для которого абсолютная сумма элементов больше. | |
fn max_abs_sum_subset_1(arr: &[i32]) -> Vec<i32> { | |
let (neg, pos): (Vec<_>, Vec<_>) = arr.iter().cloned() | |
.partition_map(|x| if x < 0 { Left(x) } else { Right(x) }); | |
let abs_sum = |arr: &[_]| arr.iter().sum::<i32>().abs(); | |
if abs_sum(&neg) > abs_sum(&pos) { neg } else { pos } | |
} | |
// Можно сделать и лучше, считая суммы при первом проходе по массиву. | |
// Для использования partition_map используемый для сбора тип должен | |
// реализовывать типажи Default (определено значение по умолчанию) | |
// и Extend (расширяется элементами из итератора). | |
#[derive(Default)] | |
struct SumSubset { | |
sum: i32, // Сумма элементов | |
set: Vec<i32>, // Сами элементы | |
} | |
impl Extend<i32> for SumSubset { | |
fn extend<I: IntoIterator<Item = i32>>(&mut self, vals: I) { | |
let vals = vals.into_iter(); | |
let (lo, hi) = vals.size_hint(); | |
self.set.reserve(hi.unwrap_or(lo)); | |
for x in vals { | |
self.sum += x; | |
self.set.push(x); | |
} | |
} | |
} | |
// Разбиваем массив на вектор отрицательных и вектор положительных, | |
// попутно считая суммы, и возвращаем тот, у которого по модулю сумма больше. | |
fn max_abs_sum_subset_2(arr: &[i32]) -> Vec<i32> { | |
let (neg, pos): (SumSubset, SumSubset) = arr.iter().cloned() | |
.partition_map(|x| if x < 0 { Left(x) } else { Right(x) }); | |
if neg.sum.abs() > pos.sum { neg.set } else { pos.set } | |
} | |
// Как и в первом случае, мы создаём два вектора (=две аллокации в куче), | |
// один из которых обязательно уничтожается при выходе из функции. | |
// Мы можем сократить потребление памяти, сначала подсчитав суммы | |
// и лишь потом вернув нужные элементы на основании того, какая сумма больше. | |
fn max_abs_sum_subset_3(arr: &[i32]) -> Vec<i32> { | |
let (mut neg_sum, mut pos_sum) = (0i32, 0i32); | |
arr.iter().for_each(|&x| if x < 0 { neg_sum -= x} else { pos_sum += x }); | |
if neg_sum > pos_sum { | |
arr.iter().cloned().filter(|&x| x < 0).collect() | |
} else { | |
arr.iter().cloned().filter(|&x| x > 0).collect() | |
} | |
} | |
fn main() { | |
// Все три способа эквивалентны и потому дают один и тот же результат | |
let arr = &[-1, 2, -1, 3, -4]; //Ответ: [-1, -1, -4] | |
println!("{:?}", max_abs_sum_subset_1(arr)); | |
println!("{:?}", max_abs_sum_subset_2(arr)); | |
println!("{:?}", max_abs_sum_subset_3(arr)); | |
let arr = &[-1, 2, -3, 2, -2, 8]; //Ответ: [2, 2, 8] | |
println!("{:?}", max_abs_sum_subset_1(arr)); | |
println!("{:?}", max_abs_sum_subset_2(arr)); | |
println!("{:?}", max_abs_sum_subset_3(arr)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment