Интересным выглядит способ, как красиво декомпозировать решение.
Для этого мы выделим итератор по всем кортежам {(x,y) | x+y=z
} в отдельный метод.
use std::collections::HashMap;
use std::cmp::Ordering;
impl Solution {
pub fn len_longest_fib_subseq(arr: Vec<i32>) -> i32 {
let n = arr.len();
let mut dp: HashMap<(i32, i32), i32> = HashMap::new(); // DP table storing lengths of valid subsequences
// Iterate over each element z as a potential end of a Fibonacci-like sequence
for k in 2..n {
let z = arr[k];
// Use an iterator to find all valid pairs (x, y) where x + y = z
for (x, y) in Self::pair_sum_iterator(arr[..k].iter(), z) {
// Apply DP transition: dp[z, y] = dp[y, x] + 1, defaulting to 2 if not found
let cur_len = dp.get(&(y, x)).unwrap_or(&2) + 1;
// Store computed length for (z, y)
dp.insert((z, y), cur_len);
}
}
// Return the longest found subsequence length, or 0 if none exist
*dp.values().max().unwrap_or(&0)
}
/// A helper function that iterates over pairs (x, y) in a sorted array slice,
/// finding pairs where x + y == target_sum using a two-pointer approach.
fn pair_sum_iterator<'a>(mut iter: impl DoubleEndedIterator<Item = &'a i32>, target_sum: i32) -> impl Iterator<Item = (i32, i32)> {
std::iter::from_fn(move || {
let mut front = iter.next();
let mut back = iter.next_back();
while let (Some(&x), Some(&y)) = (front, back) {
match (x + y).cmp(&target_sum) {
Ordering::Equal => return Some((x, y)), // Found a valid pair (x, y)
Ordering::Less => front = iter.next(), // Increase x to increase the sum
Ordering::Greater => back = iter.next_back(), // Decrease y to reduce the sum
}
}
None
})
}
}
перейти
На практических масштабах решение со сложностью O(N²logN)
(сложить все произведения в вектор, который потом отсортировать и посчитать частоты по нему) работает немного (на 20%) быстрее.
Хороший пример, когда константа от хэш-таблицы даёт больший вклад, чем логарифм от сортировки!
impl Solution {
pub fn tuple_same_product(nums: Vec<i32>) -> i32 {
// Build vector of products for all unique pairs.
let mut products: Vec<_> = (1..nums.len())
.flat_map(|j| (0..j).map(|i| nums[i] * nums[j]).collect::<Vec<_>>())
.collect();
// Sort to group identical products.
products.sort_unstable();
// Group products, calculate frequency-based contributions, and sum them.
4 * products.chunk_by(|a, b| a == b)
.filter_map(|group| if group.len() > 1 {Some(group.len() as i32)} else {None})
.map(|freq| freq * (freq - 1))
.sum::<i32>()
}
}
перейти
Стоит также обратить внимание на чуть более медленное, зато короткое решение через стабильную сортировку
impl Solution {
pub fn pivot_array(mut nums: Vec<i32>, pivot: i32) -> Vec<i32> {
nums.sort_by_key(|&num| num.cmp(&pivot)); nums
}
}
перейти
@
finder
Посмотри, пожалуйста, почему обещаемая в документации "быстрая ссылка на википедию" не срабатывает у меня:
[[Алгоритм_Кнута_—Морриса—_Пратта]]
перейти
Я, видимо, туплю, хеш-таблицы-то зачем? Двух массивов хватило бы?
перейти
Опять я провалил АА, что ж такое-то.
Если серьезно, то это пример, когда литкод-стайл измеряет не просто не то же самое, что нужно потом на работе, а прямо противоположную вещь. Сама задача очень простая, но, оказывается, можно ошибиться вот так. При этом в работе думать о том, что фраза "Даны шарики с уникальными метками от 0 до limit (всего limit + 1 шариков)" может означать, что их может оказаться миллиард, натурально вредно. Речь не о том, что не нужно оптимизировать заранее (иначе пол-литкода можно было бы стереть), но ограничения на количества объектов и операций обычно читаются из физического смысла происходящего. Запросов или, там, транзакций может быть миллиард, пользователей уже вряд ли, если вы не Мета, а шариков будут десятки, может, сотни. Особенно если они перенумерованные (а не снабженные, скажем, guid-ами).
перейти
Как будто бы, ты слишком строк к себе!
Не понять интервьюера не является грехом. Важно же, просто уметь быстро перестраивать своё решение, если что-то было изначально понято неправильно. И как раз обладание таким скилом, на мой взгляд, является гипер-полезным в рабочем процессе. И отлично, если ты его сумел показать на собеседовании!
перейти
В ограничениях задачи - шариков может быть до миллиарда: никто не гарантирует, что все бесцветные шарики в памяти уложатся.
В подходе с хэш-таблицей мы только цветные шарики храним в памяти, а их не больше, чем число операций.
перейти