Алгоритм сортировки, который не позволяет считать элементы - PullRequest
6 голосов
/ 12 июля 2011

Я видел перекосы в тесте на собеседовании в компании, но сначала я не совсем понял этот вопрос.Не могли бы вы, люди, прояснить мои сомнения?

Вопрос: Напишите программу для сортировки целочисленного массива, который содержит только 0, 1 и 2.Подсчет элементов недопустим, ожидается, что вы будете делать это за O (n) временных сложностей.

Ex Array: {2, 0, 1, 2, 1, 2, 1, 0, 2, 0}

Ответы [ 9 ]

10 голосов
/ 12 июля 2011

Вывод в связанный список.

  • Запомните начало списка.
  • Запомните позицию, с которой начинаются единицы.
  • Запомните конец списка.

Выполнить через весь массив.

  • Если вы встретите 0, добавьте его в первую позицию связанного списка.
  • Если вы встретите 1, добавьте его после позиции 1.
  • Если вы встретите 2, добавьте его в конец списка.

НТН

Рака

4 голосов
/ 12 июля 2011

Вместо того, чтобы взрывать вас еще одним непонятным псевдокодом, я дам вам название проблемы: эта проблема известна как проблема национального флага Нидерландов (первая предложенный Эдсгаром Дейкстрой) и может быть решен путем тройного слияния (см. код PHP в первом ответе, который решает эту проблему, хотя и очень неэффективно).

Более эффективное решение трехстороннего слияния на месте описано в оригинальной статье Бентли и Макилроя Разработка функции сортировки . Он использует четыре индекса для разграничения диапазонов промежуточного массива, который имеет несортированные значения в середине, 1-е на обоих краях и 0 и 2-е между:

threeways merge

После установления этого инварианта = части (то есть единицы) меняются местами в середине.

3 голосов
/ 12 июля 2011

Зависит от того, что вы подразумеваете под «не разрешено считать».

Одним из простых способов сделать это было бы иметь новый пустой массив, а затем искать 0, добавляя их в новый массив. Повторите для 1, а затем 2, и это отсортировано по времени O (n).

Но это более или менее радикальная сортировка. Как будто мы считаем 0, затем 1, затем 2, поэтому я не уверен, что это соответствует вашим критериям.


Edit: мы могли бы сделать это только с O (1) дополнительной памятью, сохраняя указатель для нашей точки вставки (начиная с начала массива), и просматривая массив на 0, заменяя каждый 0 на элемент, где указатель есть, и увеличивается указатель. Затем повторите для 1, 2 и это все еще O (n).

Реализация Java:

import java.util.Arrays;

public class Sort 
{
    public static void main(String[] args)
    {
        int[] array = {2, 0, 1, 2, 1, 2, 1, 0, 2, 0};
        sort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void sort(int[] array)
    {
        int pointer = 0;
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < array.length; j++)
            {
                if(array[j] == i)
                {
                    int temp = array[pointer];
                    array[pointer] = array[j];
                    array[j] = temp;
                    pointer++;
                }
            }
        }
    }
}

Дает вывод:

[0, 0, 0, 1, 1, 1, 2, 2, 2, 2]

1 голос
/ 12 июля 2011

В O (n) псевдокод:

def sort (src):
    # Create an empty array, and set pointer to its start.

    def dest as array[sizeof src]
    pto = 0

    # For every possible value.

    for val in 0, 1, 2:
        # Check every position in the source.

        for pfrom ranges from 0 to sizeof(src):
            # And transfer if matching (includes update of dest pointer).
            if src[pfrom] is val:
                dest[pto] = val
                pto = pto + 1

    # Return the new array (or transfer it back to the source if desired).

    return dest

Это в основном итерация по списку источников три раза, добавление элементов, если они соответствуют значению, требуемому на этом проходе.Но это все равно O (n).

Эквивалентный код Java будет:

class Test {
    public static int [] mySort (int [] src) {
        int [] dest = new int[src.length];
        int pto = 0;

        for (int val = 0; val < 3; val++)
            for (int pfrom = 0; pfrom < src.length; pfrom++)
                if (src[pfrom] == val)
                    dest[pto++] = val;
        return dest;
    }

    public static void main(String args[]) {
        int [] arr1 = {2, 0, 1, 2, 1, 2, 1, 0, 2, 0};
        int [] arr2 = mySort (arr1);
        for (int i = 0; i < arr2.length; i++)
            System.out.println ("Array[" + i + "] = " + arr2[i]);
    }
}

, который выдает:

Array[0] = 0
Array[1] = 0
Array[2] = 0
Array[3] = 1
Array[4] = 1
Array[5] = 1
Array[6] = 2
Array[7] = 2
Array[8] = 2
Array[9] = 2

А если серьезно, еслипотенциальный работодатель задал мне этот вопрос, я бы прямо заявил, что могу ответить на вопрос, если они того пожелают, но что правильный ответ - просто использовать Array.sort.Тогда если и только , если есть проблема с производительностью этого метода и конкретных наборов данных, вы можете исследовать более быстрый способ.

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

Если вы ответите мне на этот вопрос таким образом, я найму вас на месте.

1 голос
/ 12 июля 2011

Извините, это php, но, кажется, O (n), и его легко написать на java:)

$arr = array(2, 0, 1, 2, 1, 2, 1, 0, 2, 0);

$tmp = array(array(),array(),array());
foreach($arr as $i){
    $tmp[$i][] = $i;
}
print_r(array_merge($tmp[0],$tmp[1],$tmp[2]));
0 голосов
/ 12 июля 2011

Вы можете сделать это за один проход, поместив каждый встреченный элемент в свою конечную позицию:

void sort012(int* array, int len) {
    int* p0 = array;
    int* p2 = array + len;
    for (int* p = array; p <= p2; ) {
        if (*p == 0) {
            std::swap(*p, *p0);
            p0++;
            p++;
        } else if (*p == 2) {
            std::swap(*p, *p2);
            p2--;
        } else {
            p++;
        }
    }
}
0 голосов
/ 12 июля 2011

Push и Pull имеют постоянную сложность!

  1. Вставка каждого элемента в приоритетную очередь

  2. Вытянуть каждый элемент к индексам 0 ... n

(:

0 голосов
/ 12 июля 2011

Этот ответ не считает элементы.

Поскольку в массиве так мало значений, просто посчитайте, сколько существует каждого типа, и используйте его для повторного заполнения массива.,Мы также используем тот факт, что значения являются последовательными от 0 до - это соответствует типичному циклу Java.

public static void main(String[] args) throws Exception
{
    Integer[] array = { 2, 0, 1, 2, 1, 2, 1, 0, 2, 0 };
    List<Integer>[] elements = new ArrayList[3]; // To store the different element types

    // Initialize the array with new lists
    for (int i = 0; i < elements.length; i++) elements[i] = new ArrayList<Integer>();

    // Populate the lists
    for (int i : array) elements[i].add(i);

    for (int i = 0, start = 0; i < elements.length; start += elements[i++].size())
        System.arraycopy(elements[i].toArray(), 0, array, start, elements[i].size());

    System.out.println(Arrays.toString(array));
}

Вывод:

[0, 0, 0, 1, 1, 1, 2, 2, 2, 2]
0 голосов
/ 12 июля 2011

Поскольку в массиве так мало значений, просто посчитайте , сколько каждого типа существует, и используйте его для повторного заполнения массива.Мы также используем тот факт, что значения являются последовательными от 0 до - что делает его соответствующим типичному циклу Java.

Весь алгоритм сортировки требует только трех строк кода:

public static void main(String[] args)
{
    int[] array = { 2, 0, 1, 2, 1, 2, 1, 0, 2, 0 };

    // Line 1: Define some space to hold the totals
    int[] counts = new int[3]; // To store the (3) different totals

    // Line 2: Get the total of each type
    for (int i : array) counts[i]++;

    // Line 3: Write the appropriate number of each type consecutively back into the array:
    for (int i = 0, start = 0; i < counts.length; start += counts[i++]) Arrays.fill(array, start, start + counts[i], i);

    System.out.println(Arrays.toString(array));
}

Вывод:

[0, 0, 0, 1, 1, 1, 2, 2, 2, 2]

Мы ни разу не ссылались на array.length, неважно, какой длины был массив.Он повторял массив, касаясь каждого элемента только один раз, делая этот алгоритм O (n) по мере необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...