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

Новый день - новая задача 2109. Adding Spaces to a String.

Условие 🧩

Дана строка s и массив индексов spaces. Нужно добавить пробелы перед символами строки, расположенными по данным индексам, и вернуть новую строку. Например, для s = "EnjoyYourCoffee" и spaces = [5, 9] результатом будет "Enjoy Your Coffee".

Если решать абы как, то можно и в ней запутаться в индексах. Мы же будем делать все максимально просто.

Идея решения 🧠

Вместо создания промежуточных строк или модификации исходной строки, мы используем построение строки с выделением памяти заранее, чтобы минимизировать накладные расходы.

Подход 🔍

  1. Предварительно выделяем память для результирующей строки с помощью String::with_capacity, учитывая длину строки и количество пробелов.
  2. Проходим по массиву индексов spaces:
    • Добавляем в результат подстроку от предыдущей позиции до текущего индекса.
    • Добавляем пробел.
  3. После цикла добавляем оставшуюся часть строки.
  4. Возвращаем итоговую строку.

Анализ сложности 📊

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

impl Solution {
    pub fn add_spaces(s: String, spaces: Vec<i32>) -> String {
        let mut result = String::with_capacity(s.len() + spaces.len()); // Pre-allocate capacity for efficiency
        let mut word_pos = 0;

        for &space_pos in &spaces {
            let space_pos = space_pos as usize; // Convert i32 to usize for indexing
            result.push_str(&s[word_pos..space_pos]); // Add the substring
            result.push(' '); // Add the space
            word_pos = space_pos;
        }

        result.push_str(&s[word_pos..]); // Add the remaining substring
        result
    }
}

2 leetcoder 03-12-2024

Ещё один простой вариант решения - собрать все слайсы, отвечающие словам в одну коллекцию и проджойнить стандартными средствами через пробел.

impl Solution {
    pub fn add_spaces(s: String, spaces: Vec<i32>) -> String {
        // Convert indices to usize
        let mut spaces: Vec<usize> = spaces.into_iter().map(|s_pos| s_pos as usize).collect();

        // Add the start (0) and end (s.len()) boundaries to spaces
        spaces.insert(0, 0);
        spaces.push(s.len());

        // Create slices from spaces indices
        let slices: Vec<&str> = spaces.windows(2)
            .map(|window| &s[window[0]..window[1]])
            .collect();

        // Join the slices with spaces
        slices.join(" ")
    }
}

В этом коде есть один грустный момент - необходимость создания промежуточного вектора из слайсов исходной строки.
К сожалению, join из стандартной библиотеки позволяет только такое использование.
Но, если мы не ограничеы стандартной библиотекой, то крейт itertools спешит нам на помощь ;)

ответить
1 leetcoder 03-12-2024

Еще немного покопался и есть всё же способ достичь желаемого эффекта только со стандартной библиотекой

impl Solution {
    pub fn add_spaces(s: String, spaces: Vec<i32>) -> String {
        // Convert indices to usize
        let mut spaces: Vec<usize> = spaces.into_iter().map(|s_pos| s_pos as usize).collect();

        // Add the start (0) and end (s.len()) boundaries to spaces
        spaces.insert(0, 0);
        spaces.push(s.len());

        // Use flat_map to create slices and spaces, take appropriate elements 
        // and collect to result string
        spaces.windows(2)
            .flat_map(|window| [&s[window[0]..window[1]], " "])
            .take(2 * spaces.len() - 3) // Take the correct number of slices and spaces
            .collect::<String>()
    }
}
ответить