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

Сегодня у нас еще одна задача на аккуратное манипулирование индексами 2337. Move Pieces to Obtain a String.

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

Даны две строки start и target длины n, содержащие символы 'L', 'R' и '_'.

Идея 🧠

Задача сводится к тому, чтобы проверить, совпадают ли позиции и направления символов 'L' и 'R' в двух строках с учётом их ограничений на движение. Мы используем итерацию по строкам одновременно, отслеживая доступные символы 'L' и 'R' через счётчики.

Подход 🛠️

  1. Используем метод as_bytes(), чтобы быстро перебрать символы в виде байтов.
  2. Одновременно проходим по обеим строкам:
    • Если видим 'L' в target, увеличиваем счётчик доступных 'L'.
    • Если видим 'L' в start, проверяем, есть ли доступный 'L', и уменьшаем счётчик.
    • Аналогично для 'R'
    • Также проверяем, что 'R' не пересекает 'L', и аккуратно в правильном порядке синхронизируем счётчики.
  3. В конце проверяем, что все 'L' и 'R' учтены (баланс счётчиков нулевой).

Сложность 📊

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

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

impl Solution {
    pub fn can_change(start: String, target: String) -> bool {
        let mut left_pieces = 0;  // Tracks available 'L' pieces
        let mut right_pieces = 0; // Tracks available 'R' pieces

        for (&start_char, &target_char) in 
                start.as_bytes().iter().zip(target.as_bytes().iter()
        ) {
            // Check for target_char == 'L'
            if target_char == b'L' {
                if right_pieces > 0 {
                    return false; // 'L' cannot cross 'R'
                }
                left_pieces += 1;
            }

            // Check for start_char == 'L'
            if start_char == b'L' {
                if left_pieces <= 0 {
                    return false; // No available 'L' to move
                }
                left_pieces -= 1;
            }

            // Check for start_char == 'R'
            if start_char == b'R' {
                if left_pieces > 0 {
                    return false; // 'R' cannot cross 'L'
                }
                right_pieces += 1;
            }

            // Check for target_char == 'R'
            if target_char == b'R' {
                if right_pieces <= 0 {
                    return false; // 'R' must have a matching piece
                }
                right_pieces -= 1;
            }
        }

        // All pieces should be accounted for
        left_pieces == 0 && right_pieces == 0
    }
}

Полезное замечание

1 voodookiidoo 18 ч назад

опять же поделюс своим решением тоже!
хотя оно не такое оптимальное судя по всему)

use std::iter::zip;

impl Solution {
    pub fn can_change(start: String, target: String) -> bool {
        {
            let s1 = start.chars().filter(|it| *it != '_').collect::<String>();
            let s2 = target.chars().filter(|it| *it != '_').collect::<String>();
            if s1 != s2 {
                return false;
            }
        };
        let lindices1 = Self::collect(&start, 'L');
        let rincides1 = Self::collect(&start, 'R');
        let lindices2 = Self::collect(&target, 'L');
        let rindices2 = Self::collect(&target, 'R');
        for (l1, l2) in zip(lindices1, lindices2){
            if l1 <= l2{
                return false
            }
        }
        for (r1, r2) in zip(rincides1, rindices2){
            if r1 >= r2{
                return false
            }
        }
        true
    }
    fn collect(s:&str, target:char)->Vec<usize>{
        s.char_indices().filter(|(_, ch)|*ch == 'L').map(|it|it.0).collect()
    }
}
ответить
1 leetcoder 1 ч назад

Я бы это решение предложил доработать, избавив его от разбросанных по соду .collect() с агрегацией в памяти.
По сути можно логику только на итераторах оставить и получить достаточно эффективное 3-х проходное решение без дополнительной памяти из твоего.

ответить