Условие задачи — 2503. Maximum Number of Points From Grid Queries.
📘 Условие задачи
- Дана матрица
grid
размером m × n
и массив целых чисел queries
, каждый из которых представляет пороговое значение.
- Для каждого запроса
queries[i]
необходимо определить, сколько уникальных ячеек можно достичь, начиная с (0, 0)
, если разрешено:
- двигаться вверх, вниз, влево и вправо;
- заходить только в те ячейки, значение которых строго меньше
queries[i]
;
- Нужно вернуть массив
result
, где result[i]
— это общее количество очков, полученных для queries[i]
.
💡 Идея
Вместо того чтобы запускать поиск заново для каждого запроса, можно:
- выполнить один глобальный обход BFS, начиная с
(0, 0)
;
- посещать ячейки по возрастанию их значений (с помощью min-heap);
- на лету отвечать на все запросы, чьё значение не превышает текущей ячейки.
Такой метод за 1 проход отвечает сразу на все запросы.
🛠️ Детали реализации
- Сохраняем исходные индексы запросов и сортируем их по значениям.
- Запускаем BFS с приоритетом по значениям (
BinaryHeap
с Reverse
), начиная с (0, 0)
.
- При достижении новой ячейки:
- если её значение превышает предыдущий лимит, обновляем результат для всех
queries[i] ≤ value
;
- увеличиваем счётчик посещённых ячеек.
- Обрабатываем все возможные ячейки.
- В конце заполняем ответы на оставшиеся запросы.
⏱️ Асимптотики
- Время:
O(mn·log mn + k·log k)
O(mn·log mn)
— операции добавления и извлечения из кучи при BFS
O(k·log k)
— сортировка запросов
- Память:
O(mn + k)
O(mn)
— матрица посещений и верхняя граница для количества элементов в куче
O(k)
— массив индексов запросов
🧾 Исходный код
use std::collections::BinaryHeap;
use std::cmp::Reverse;
impl Solution {
pub fn max_points(grid: Vec<Vec<i32>>, queries: Vec<i32>) -> Vec<i32> {
let k = queries.len();
// Store original indices of the queries
let mut sorted_indices: Vec<usize> = (0..k).collect();
sorted_indices.sort_unstable_by_key(|&i| queries[i]);
let mut result = vec![0; k];
let mut query_ptr = 0;
// Callback closure to update result for all queries with value ≤ limit
let mut set_answers = |limit: i32, count: i32| {
while query_ptr < k && queries[sorted_indices[query_ptr]] <= limit {
result[sorted_indices[query_ptr]] = count;
query_ptr += 1;
}
};
Self::bfs_with_threshold_callback(&grid, &mut set_answers);
result
}
fn bfs_with_threshold_callback<F>(grid: &[Vec<i32>], callback: &mut F)
where
F: FnMut(i32, i32),
{
let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)];
let m = grid.len();
let n = grid[0].len();
let mut visited = vec![vec![false; n]; m];
let mut heap = BinaryHeap::new();
let mut count = 0;
let mut limit = 0;
heap.push(Reverse((grid[0][0], 0, 0)));
visited[0][0] = true;
while let Some(Reverse((value, row, col))) = heap.pop() {
// Trigger callback when reaching a higher threshold
if value > limit {
callback(value, count);
limit = value;
}
count += 1;
for (dr, dc) in directions {
let r = row as isize + dr;
let c = col as isize + dc;
if r >= 0 && r < m as isize && c >= 0 && c < n as isize {
let r = r as usize;
let c = c as usize;
if !visited[r][c] {
visited[r][c] = true;
heap.push(Reverse((grid[r][c], r, c)));
}
}
}
}
// Final callback to assign remaining unanswered queries
callback(i32::MAX, count);
}
}
Tags: #rust #algorithms #bfs