it-swarm.com.ru

Учитывая массив целых чисел, найдите первое отсутствующее положительное целое число в линейном времени и постоянном пространстве

Другими словами, найдите наименьшее положительное целое число, которое не существует в массиве. Массив может содержать как дубликаты, так и отрицательные числа . Этот вопрос был задан Stripe в интервью по программированию. Я разработал решение для того же, что и ниже:

#include<bits/stdc++.h>
using namespace std;

int main(){
    int arr[]={1,-1,-5,-3,3,4,2,8};
    int size= sizeof(arr)/sizeof(arr[0]);
    sort(arr, arr+size);
    int min=1;

    for(int i=0; i<size; i++){
        if(arr[i]>min) break;
        if(arr[i]==min) min=min+1;
    }
    cout<<min;
    return 0;
}

Здесь я сначала сортирую массив, а затем перебираю массив один раз. Перед обходом массива я инициализировал переменную с именем min как 1. Теперь, при обходе массива, когда мы получаем целое число, равное min, мы просто увеличиваем значение min. Это гарантирует, что переменная min содержит последнее наименее положительное целое число, которое еще не произошло. Можете ли вы придумать лучший подход? Заранее спасибо.

3
Jhanak Didwania

Предполагая, что массив может быть изменен,

  1. Разобьем массив на 2 части так, чтобы первая часть состояла только из положительных чисел. Скажем, у нас есть начальный индекс как 0 и конечный индекс как end (исключая).

  2. Мы пересекаем массив из индекса 0 в end. Мы берем абсолютное значение элемента по этому индексу - скажем, значение x

    1. Если x > end мы ничего не делаем. 
    2. Если нет, мы делаем знак элемента с индексом x-1 отрицательным.
  3. Наконец, мы еще раз переходим массив из индекса 0 в end. В случае, если мы встречаем положительный элемент по какому-либо индексу, мы выводим index + 1. Это ответ. Однако, если мы не встречаем никаких положительных элементов, это означает, что в массиве встречаются целые числа от 1 до end. Мы выводим end + 1

Это также может быть случай, когда все числа не положительны, что делает end = 0. Вывод end + 1 = 1 остается верным.

Все шаги могут быть выполнены за время O(n) и пространство O(1).

Пример:

Initial Array:            1 -1 -5 -3 3 4 2 8
Step 1 partition:         1 8 2 4 3 | -3 -5 -1, end = 5

На шаге 2 мы меняем знаки положительных чисел, чтобы отслеживать, какие целые числа уже произошли. Например, здесь array[2] = -2 < 0 предполагает, что 2 + 1 = 3 уже присутствовал в массиве. По сути, мы меняем значение элемента, имеющего индекс i, на отрицательное, если i+1 находится в массиве.

Step 2 Array changes to: -1 -8 -2 -4 3 | -3 -5 -1

На шаге 3, если какое-то значение array[index] положительное, это означает, что мы не нашли целое число значения index + 1 на шаге 2.

Step 3: Traversing from index 0 to end, we find array[4] = 3 > 0
        The answer is 4 + 1 = 5
3
pmcarpan

Алгоритм PMCarpan работает.

Я думаю, что ваш подход работает, но вы должны указать тип сортировки, который вы делаете, чтобы было ясно, что это линейная сортировка и не обязательно полная сортировка всего массива. Это приводит к O(N) времени без использования пробела. 

Просканируйте массив, так как вы сканируете, если значение в вашем текущем индексе меньше длины массива, затем замените его на текущее значение в этом индексе. Вы должны продолжать менять местами, пока не перестанет иметь смысл менять каждый индекс. Затем в конце выполните еще одно сканирование, пока не найдете неверный индекс.

Вот некоторый рабочий код на python, хотя python не место для подобных вещей, смеется.

def sortOfSort(arr) :
    for index in range(len(arr)) :
        checkValue = arr[index]

        while(checkValue > 0 and checkValue != index and checkValue < len(arr) and arr[checkValue] != checkValue) :
            arr[index] = arr[checkValue]
            arr[checkValue] = checkValue
            checkValue = arr[index]

    return arr[1:] + [arr[0]]

def findFirstMissingNumber(arr) :
    for x in range(len(arr)) :
        if (x+1 != arr[x]) :
            return x+1
    return len(arr) + 1

возвращаемая часть arr [1:] потому что, исходя из вашего описания, мы не включаем ноль в качестве отправной точки.

0
FredMan

Предполагая, что этот список можно изменить на месте.
Идея: Используйте значения списка (в пределах диапазона), чтобы самостоятельно «пометить» индексы списка. Вернуть наименьший индекс без тегов из этого списка тегов.
Например, если список состоит из 4 цифр, то значение "2" приведет к тому, что индекс 1 будет помечен ...
Я использую комплексные числа для «пометки», так как он сохраняет значение в реальной части. Т.е. добавление 1j к значению «помечает» его, в то время как само значение все еще можно восстановить в реальной части ...

Смотрите реализацию Python3:

def foo(int_list):
    # "Tag" list values in-place
    # O(n)
    for i in int_list:
        # Remove imaginary "tag"
        if i.imag > 0:
            i = int(i.real)
        # Check positive i ints that are less than len(int_list)
        if 0 < i < len(int_list):
            # Add imaginary "tag"
            int_list[i-1] = (1j + int_list[i-1])

    # Iterate over the int_list
    # O(n)
    ctr = 0
    while ctr < len(int_list):
        # Return the first "un-tagged" index (+1)
        if int_list[ctr].imag == 0:
            return ctr + 1
        ctr += 1
    else:
        return len(int_list)


assert foo([3, 4, -1, 1]) == 2
assert foo([3, 4, 4, 4, 4, -1, 1]) == 2
assert foo([1, 2, 0]) == 3
assert foo([8, 1, 7]) == 2
0
pX0r