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

Очередная задача — 2375. Construct Smallest Number From DI String сходу выглядит переборной, но может быть эффективно реализована за счёт использования графовых алгоритмов.

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

Дан строковый шаблон pattern, состоящий из символов I и D.
Необходимо построить лексикографически наименьшее число длины n+1, используя цифры от 1 до 9 без повторений, которое соответствует следующим требованиям:

💡 Идея

Рассмотрим шаблон как ориентированный граф, где каждая позиция (i) — это вершина.

После построения графа можно выполнить топологическую сортировку, начиная с вершин с нулевой степенью захода.
Чтобы гарантировать лексикографически наименьший порядок, обрабатываем вершины через приоритетную очередь (Min-Heap).

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

  1. Построение графа
    • Создаём список смежности (graph) и массив степеней захода (in_degree).
    • 'I' → добавляем ребро i → i+1, увеличиваем in_degree[i+1].
    • 'D' → добавляем ребро i+1 → i, увеличиваем in_degree[i].
  2. Инициализация Мин-Кучи
    • Добавляем все вершины с нулевой степенью захода в Min-Heap.
  3. Топологическая сортировка
    • Достаём минимальную вершину из кучи, назначаем ей следующую минимальную цифру.
    • Уменьшаем степени захода её соседей.
    • Если у соседа становится нулевая степень захода, добавляем его в Min-Heap.
  4. Формируем результат
    • После обработки всех вершин собираем итоговую строку.

⏳ Асимптотика

📜 Исходный код

use std::collections::BinaryHeap;
use std::cmp::Reverse;

impl Solution {
    pub fn smallest_number(pattern: String) -> String {
        let n = pattern.len() + 1;

        // Step 1: Build graph and compute in-degree
        let mut graph = vec![Vec::new(); n];
        let mut in_degree = vec![0; n];

        for (i, ch) in pattern.chars().enumerate() {
            if ch == 'I' {
                graph[i].push(i + 1); // i → i+1
                in_degree[i + 1] += 1;
            } else {
                graph[i + 1].push(i); // i+1 → i
                in_degree[i] += 1;
            }
        }

        // Step 2: Initialize min-heap with zero in-degree nodes
        let mut min_heap = BinaryHeap::new();
        for i in 0..n {
            if in_degree[i] == 0 {
                min_heap.push(Reverse(i)); // Reverse to create a min-heap
            }
        }

        // Step 3: Process nodes in topological order
        let mut result = vec![' '; n];
        let mut next_digit = '1';

        while let Some(Reverse(node)) = min_heap.pop() {
            result[node] = next_digit;
            next_digit = ((next_digit as u8) + 1) as char;

            for &neighbor in &graph[node] {
                in_degree[neighbor] -= 1;
                if in_degree[neighbor] == 0 {
                    min_heap.push(Reverse(neighbor));
                }
            }
        }

        result.into_iter().collect()
    }
}

Tags: #rust #algorithms #graph