главная новое лучшее написать
2

Описание задачи 📝

У нас есть массив heights, где heights[i] представляет высоту здания i.
Также даны запросы в виде массива queries, где каждый запрос [ai,bi>] требует определить самое левое здание, на которое могут попасть Алиса и Боб, начав с ai​ и bi​ соответственно, при соблюдении следующих условий:

Если подходящее здание невозможно найти, результат для данного запроса равен −1.

Идея 💡

Мне сходу не известна эффективная структура данных для онлайн-разрешения запросов.
Но можно поступить хитрее, а именно:

Детали подхода 🛠️

  1. Предварительная обработка запросов:
    • Разделяем запросы на "простые" и "сложные". "Простые" запросы немедленно записываем в результат.
    • "Сложные" запросы сохраняем как структуры MaxQuery для последующей обработки.
  2. Сортировка запросов:
    • Сортируем "сложные" запросы по индексу правого здания.
  3. Решение с помощью кучи:
    • Итеративно проходим по массиву зданий (heights).
    • Для каждого здания:
      • Добавляем в кучу все запросы, которые нужно обработать, начиная с текущего индекса.
      • Разрешаем запросы в куче, проверяя минимальную высоту из запроса по сравнению с текущей высотой здания.

Асимптотика ⏱️💾

Исходный код решения 💻

use std::collections::BinaryHeap;

#[derive(Eq, PartialEq, Clone)]
struct MaxQuery {
    value: i32,
    index: usize,
    query_idx: usize,
}

impl Solution {
    pub fn leftmost_building_queries(heights: Vec<i32>, queries: Vec<Vec<i32>>) -> Vec<i32> {
        let mut results = vec![-1; queries.len()];
        let mut deferred_queries = Vec::new();

        // Prepare queries
        for (idx, query) in queries.iter().enumerate() {
            let (mut l, mut r) = (query[0] as usize, query[1] as usize);
            if l > r {
                (l, r) = (r, l);
            }
            if l == r || heights[r] > heights[l] {
                results[idx] = r as i32;
            } else {
                deferred_queries.push(MaxQuery::new(heights[l], r, idx));
            }
        }

        // Sort deferred queries by index
        deferred_queries.sort_by_key(|q| q.index);

        // Process queries using a heap
        let mut heap = BinaryHeap::new();
        let mut deferred_idx = 0;

        for (current_idx, &height) in heights.iter().enumerate() {
            // Add all queries up to the current position
            while deferred_idx < deferred_queries.len()
                && deferred_queries[deferred_idx].index <= current_idx
            {
                heap.push(deferred_queries[deferred_idx].clone());
                deferred_idx += 1;
            }

            // Resolve queries in the heap
            while let Some(top_query) = heap.peek() {
                if top_query.value < height {
                    results[top_query.query_idx] = current_idx as i32;
                    heap.pop();
                } else {
                    break;
                }
            }
        }

        results
    }
}

impl MaxQuery {
    fn new(value: i32, index: usize, query_idx: usize) -> Self {
        Self{value, index, query_idx}
    }
}

impl Ord for MaxQuery {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        other.value.cmp(&self.value)
    }
}

impl PartialOrd for MaxQuery {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}