Сложный уровень

Легкий

Спросил в

Facebook, Amazon, Uber, Bloomberg, Linkedin, Paytm

Обсуждены три решения

  1. Подход грубой силы - использование лишнего места
  2. Подход с использованием двух указателей - двойное сканирование
  3. Подход с использованием двух указателей - одно сканирование

Ключевые выводы после прочтения этого блога

  • Эффективное решение - это вариант подхода с двумя указателями, когда указатели движутся в одном направлении.
  • Хорошая задача - изучить оптимизацию, улучшив сложность пространства и уменьшив лишний обход.
  • Мы можем использовать аналогичные идеи для решения других проблем с кодированием.
  • Хорошая задача для новичков, чтобы начать писать код.

Давайте разберемся в проблеме

Для массива X [] из n элементов, заполненных несколькими целыми числами, некоторые из которых являются нулями, напишите программу для перемещения всех нулей в конец.

Примеры

Input: X[] = [4, 8, 6, 0, 2, 0, 1, 15, 12, 0]
Output: [4, 8, 6, 2, 1, 15, 12, 0, 0, 0]
Input: X[] = [0, 3, 5, 9, 0, 0, 23, 2]
Output: [3, 5, 9, 23, 2, 0, 0, 0]

Подход грубой силы: использование лишнего места

Одна из основных идей - сначала пройти по входному массиву X [] и сохранить все ненулевые элементы в дополнительной памяти Y [] размера n. Теперь заполните оставшееся пустое пространство Y [] нулями и верните его как результат.

  • Инициализируйте два указателя i и j, где указатель i предназначен для обхода входного массива X [], а j - для хранения значений в Y []. Оба указателя движутся в одном направлении.
  • Во время обхода, когда мы находим ненулевой элемент x [i], сохраняем его в Y [j] и увеличиваем как i, так и j. В противном случае просто увеличьте указатель i.

Псевдокод алгоритма

int[] moveZeroesEnd(int X[], int n)
{
    int Y[n]
    int j = 0
    for (int i = 0; i < n; i = i + 1)
    {
        if (X[i] != 0)
        {
            Y[j] = X[i]
            j = j + 1
        }
    }
    
    while (j < n)
    {
        Y[j] = 0
        j = j + 1
    }
    return Y
}

Анализ алгоритмов

Сложность времени = Сложность времени обхода X [] и сохранения ненулевых элементов в Y [] + Сложность времени сохранения нулей в Y [] = O (n) + O (n) = O ( п). Другими словами, в худшем случае мы выполняем один обход обоих массивов.

Сложность пространства = O (n) для дополнительного пространства Y [].

Подход с использованием двух указателей - двойное сканирование

Теперь критический вопрос: можем ли мы дополнительно оптимизировать вышеупомянутый алгоритм, чтобы уменьшить сложность пространства или решить проблему на месте? Давай подумаем!

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

  • Обходите входной массив, используя два указателя i и j, где i - для обхода массива, а j - для отслеживания последнего индекса ненулевого элемента.
  • Всякий раз, когда мы встречаем ненулевой элемент, мы перемещаем его в начало X [], т.е. если (X [i]! = 0), мы обновляем X [j] = X [i]. Мы также увеличиваем i и j на 1. В противном случае пропускаем нулевые элементы и перемещаем указатель i на 1.
  • После всего процесса все элементы в X [0… j-1] являются ненулевыми элементами. Теперь снова переместите X [] от j к n-1 и заполните его нулями. (Подумайте!)

Псевдокод алгоритма

void moveZeroEnd(int X[], int n)
{
    int j = 0
    for (int i = 0; i < n; i = i + 1)
    {
        if (X[i] != 0)
        {
            X[j] = X[i]
            j = j + 1
        }
    }
    while (j < n)
    {
        X[j] = 0
        j = j + 1
    }
}

Анализ алгоритмов

Сложность по времени (в худшем случае) = Сложность по времени прохождения X [] для ненулевых элементов + Сложность по времени прохождения X [] для заполнения нулей = O (n) + O (n) = На)

Мы решаем эту проблему на месте. Космическая сложность = O (1)

Использование подхода с двумя указателями - одно сканирование

Можем ли мы дополнительно оптимизировать описанный выше подход и решить его всего за один обход? Можем ли мы сократить второй обход, чтобы в итоге заполнить ноль? Давай подумаем!

В приведенном выше методе вместо присвоения X [j] X [i], если мы поменяем местами оба элемента, нам не нужно будет заполнять остальную часть массива нулями в конце. Все ненулевые элементы будут перемещены в конец за счет подкачки. Эта идея аналогична алгоритму разбиения быстрой сортировки.

Псевдокод алгоритма

void moveZeroEnd(int X[], int n)
{
    int j = 0
    for (int i = 0; i < n; i = i + 1)
    {
        if(X[i]!= 0)
        {
            swap(X[j], X[i])
            j = j + 1
        }
    }    
}

Анализ алгоритмов

Мы делаем только один обход, где сравнение и замена являются критическими операциями. Сложность времени = O (n), сложность пространства = O (1)

Возможные вопросы интервьюера

  • Можем ли мы, используя аналогичный подход, отсортировать массив, содержащий элементы только с двумя повторяющимися значениями? Как мы решим эту проблему при повторении трех значений?
  • Какова будет полная операция подкачки в наихудшем сценарии при подходе с одним обходом?
  • Сохраняется ли относительный порядок ненулевых элементов в вышеуказанных подходах?
  • Во втором подходе, почему мы снова обходим, чтобы сохранить нули до конца входного массива?
  • Можно ли решить эту проблему другим подходом? Можем ли мы использовать два указателя в противоположном направлении?
  • Сохранят ли указанные выше подходы порядок ненулевых элементов?

Предлагаемые проблемы для решения

  • Удвойте первый элемент и переместите ноль в конец
  • Разделить четные и нечетные числа
  • Разделить нули и единицы в массиве
  • Переместите все значения, равные K, в конец массива
  • Минимальные свопы, необходимые для сортировки массива в порядке возрастания
  • Разделите массив так, чтобы сумма двух подмассивов была одинаковой.
  • Проверить наличие пары в массиве с заданной суммой

Если у вас есть идеи / вопросы / сомнения / отзывы, оставьте комментарий ниже или напишите нам по адресу [email protected]. Наслаждайтесь обучением, наслаждайтесь кодированием, наслаждайтесь алгоритмами!

Первоначально опубликовано на www.enjoyalgorithms.com/coding-interview