给定整数数组,找到线性时间和恒定空间中的第一个缺失的正整数

时间:2018-07-15 07:13:07

标签: arrays algorithm sorting array-algorithms

换句话说,找到数组中不存在的最低正整数。该数组也可以包含重复项和负数。 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变量保存尚未出现的最新的最小正整数。 您能想到更好的方法吗?预先感谢。

14 个答案:

答案 0 :(得分:7)

假设可以修改数组,

  1. 我们将数组分为两部分,使得第一部分仅包含正数。假设我们的起始索引为0,结束索引为end(不包括)。

  2. 我们遍历数组从索引0end。我们在该索引处获取元素的绝对值-假设该值为x

    1. 如果x > end,我们什么也不做。
    2. 如果不是,则使索引x-1处的元素的符号为负。
  3. 最后,我们再次从索引0end遍历数组。如果我们在某个索引处遇到一个正数元素,则输出index + 1。这就是答案。但是,如果我们没有遇到任何正数元素,则意味着在数组中出现整数1end。我们输出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]为正,则意味着在第2步中没有找到任何值index + 1的整数。

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

答案 1 :(得分:1)

我使用python3中的set解决了这个问题。这是非常简单的6LOC。 时间复杂度:O(n)。

记住:集合中的成员资格检查为O(1)

def first_missing_positive_integer(arr):
    arr = set(arr)
    for i in range(1, len(arr)+2):
        if i not in arr:
            return i

答案 2 :(得分:0)

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:]部分是因为根据您的描述,我们不将零作为起点。

答案 3 :(得分:0)

这是一个C实现
输入

#include <stdio.h>
#include <stdlib.h>
//Here we separate the positive and negative number
int separate (int arr[], int size)
{
    int j = 0, i , temp;
    for(i = 0; i < size; i++)
    {
    if (arr[i] <= 0)
    {
        /*Here we using bitwise operator to swap the
        numbers instead of using the temp variable*/
         arr[j] = arr[j]^arr[i];
         arr[i] = arr[j]^arr[i];
         arr[j] = arr[j]^arr[i];
         j++;
    }
    }
    printf("First We Separate the negetive and positive number \n");
    for( i = 0 ; i <size ; i++)
    {
        printf("Array[%d] = %d\n",i,arr[i]);
    }
    return j;
}
int findMissingPositive(int arr[], int size)
{
printf("Remove the negative numbers from array\n");
int i;
for( i = 0 ; i <size ; i++)
{
        printf("Array[%d] = %d\n",i,arr[i]);
}
for(i = 0; i < size; i++)
{
    if(abs(arr[i]) - 1 < size && arr[ abs(arr[i]) - 1] > 0)
    arr[ abs(arr[i]) - 1] = -arr[ abs(arr[i]) - 1];
}
for(i = 0; i < size; i++)
    if (arr[i] > 0)
    {
    return i+1;
    }
return size+1;
}
int findMissing(int arr[], int size)
{
int j = separate (arr, size);
return findMissingPositive(arr+j, size-j);
}
int main()
{
int size ;
printf("Enter the Value of Size of Array : ");
scanf("%d",&size);
int arr[size];
printf("Enter the values :\n");
for( int i = 0 ; i < size ; i++)
{
    printf("Array[%d] = ",i);
    scanf("%d",&arr[i]);
}
int missing = findMissing(arr,size);
printf("The smallest positive missing number is %d ", missing);
return 0;
}


输出

Enter the Value of Size of Array : 8
Enter the values :
Array[0] = 1
Array[1] = -1
Array[2] = -5
Array[3] = -3
Array[4] = 3
Array[5] = 4
Array[6] = 2
Array[7] = 8
First We Separate the negetive and positive number
Array[0] = -1
Array[1] = -5
Array[2] = -3
Array[3] = 1
Array[4] = 3
Array[5] = 4
Array[6] = 2
Array[7] = 8
Remove the negative numbers from array
Array[0] = 1
Array[1] = 3
Array[2] = 4
Array[3] = 2
Array[4] = 8
The smallest positive missing number is 5
Process returned 0 (0x0)   execution time : 27.914 s
Press any key to continue.

 /*
        How work :
        [if(abs(arr[i]) - 1 < size && arr[ abs(arr[i]) - 1] > 0)
        arr[ abs(arr[i]) - 1] = -arr[ abs(arr[i]) - 1];]
        before: arr = { 7, 3, 4, 5, 5, 3, 2}
    i == 0: arr[0] = 7
            arr[7-1] is 2 > 0 ~> negate
            arr = { 7, 3, 4, 5, 5, 3, -2}
    i == 1: arr[1] = 3
            arr[3-1] is 4 > 0 ~> negate
            arr = { 7, 3, -4, 5, 5, 3, -2}
    i == 2: arr[2] is -4 ~> abs for indexing
            arr[4-1] is 5 > 0 ~> negate
            arr = { 7, 3, -4,-5, 5, 3, -2}
    i == 3: arr[3] is -5 ~> abs for indexing
            arr[5-1] is 5 > 0 ~> negate
            arr = { 7, 3, -4, -5, -5, 3, -2}
    i == 4: arr[4] is -5 ~> abs for indexing
            arr[5-1] is -5 < 0 ~> print abs(-5) as duplicate
    i == 5: arr[5] is 3
            arr[3-1] is -4 < 0 ~> print abs(3) as duplicate
    i == 6: arr[6] is -2 ~> abs for indexing
            arr[2-1] is 3 > 0 ~> negate
            arr = { 7, -3, -4, -5, -5, 3, -2}

            indices of positive entries: 0, 5 ~> 1 and 6 not in original array
            indices of negative entries: 1, 2, 3, 4, 6 ~> 2, 3, 4, 5, 7 in original array
*/

答案 4 :(得分:0)

#Returns a slice containing positive numbers
def findPositiveSubArr(arr):
    negativeIndex = 0

    if i in range(len(arr)):
        if arr[i] <=0:
            arr.insert(negativeIndex, arr.pop(i))
            negativeIndex += 1
    return arr[negativeIndex:]

#Returns the first missing positive number
def findMissingPositive(positiveArr):
    l = len(positiveArr)
    for num in positiveArr:
        index = abs(num) - 1
        if index < 1 and positiveArr[index] > 0:
            positiveArr[index] *= -1

    for i in range(l):
        if positiveArr[i] > 0:
            return i+1

    return l+1

if __name__ == "__main__":
    arr = [int(x) for x in input().strip().split()]
    positiveSubArr = findPositveSubArr(arr)
    print(findMissingPositive(positiveSubArr))

答案 5 :(得分:0)

这要简单得多。 (解决方案不是我的)

Private Sub OpenFile_Click(sender As Object, e As EventArgs) Handles openFile.Click
    OpenFileDialog.ShowDialog()
    Dim strFileName = OpenFileDialog.FileName

    'Create the lists
    For i As Integer = 0 To UBound(game)
        game(i) = New List(Of Location)()
    Next i

    For Each textline As String In File.ReadLines(strFileName)
        Dim parts() As String = textline.Split("|"c)

        If parts.Length = 7 Then 'Not an empty line
            For g As Integer = 0 To UBound(game)
                Dim location = New Location()
                location.Name = parts(0)
                location.Distance = CDbl(parts(1 + g))
                location.Points = CInt(parts(4 + g))
                game(g).Add(location)
            Next g
        End If
    Next

    DisplayGame(game(0))
End Sub

有一个递归,但是由于每个交换将1值放到正确的位置,所以将有<= n个交换。线性时间

答案 6 :(得分:0)

这是pmcarpan's answer的Python 3实现。

def missing_int(nums: MutableSequence[int]) -> int:
    # If empty array or doesn't have 1, return 1
    if not next((x for x in nums if x == 1), 0):
        return 1

    lo: int = 0
    hi: int = len(nums) - 1
    i: int = 0
    pivot: int = 1

    while i <= hi:
        if nums[i] < pivot:
            swap(nums, i, hi)
            hi -= 1
        elif nums[i] > pivot:
            swap(nums, i, lo)
            i += 1
            lo += 1
        else:
            i += 1

    x = 0
    while x <= hi:  # hi is the index of the last positive number
        y: int = abs(nums[x])
        if 0 < y <= hi + 1 and nums[y - 1] > 0:  # Don't flip sign if already negative
            nums[y - 1] *= -1
        x += 1

    return next((i for i, v in enumerate(nums[:hi + 1]) if v >= 0), x) + 1

测试:

def test_missing_int(self):
    assert func.missing_int([1, 2, 1, 0]) == 3
    assert func.missing_int([3, 4, -1, 1]) == 2
    assert func.missing_int([7, 8, 9, 11, 12]) == 1
    assert func.missing_int([1]) == 2
    assert func.missing_int([]) == 1
    assert func.missing_int([0]) == 1
    assert func.missing_int([2, 1]) == 3
    assert func.missing_int([-1, -2, -3]) == 1
    assert func.missing_int([1, 1]) == 2
    assert func.missing_int([1000, -1]) == 1
    assert func.missing_int([-10, -3, -100, -1000, -239, 1]) == 2
    assert func.missing_int([1, 1]) == 2

答案 7 :(得分:0)

这是Java语言。时间复杂度f O(N)和空间复杂度O(1)

private static int minimum_positive_integer(int[] arr) {
        int i = 0;
        int j = arr.length - 1;

        //splitting array
        while (i < j) {
            if (arr[i] > 0) {
                i++;
            }

            if (arr[j] <= 0) {
                j--;
            }

            if (arr[i] <= 0 && arr[j] > 0) {
                int t = arr[i];
                arr[i] = arr[j];
                arr[j] = t;

                i++;
                j--;
            }
        }
        int len_positive = i;

        if (arr[i] > 0) len_positive++;

        for (i = 0; i < len_positive; i++) {
            int abs = Math.abs(arr[i]);
            if (abs <= len_positive) {
                int index = abs - 1;
                arr[index] = -abs;
            }
        }

        for (i = 0; i < len_positive; i++) {
            if(arr[i] > 0) return  i + 1;
        }

        return len_positive + 1;
    }

答案 8 :(得分:0)

我在Python中的解决方案:

def lowest_positive(lista):

result = 0
dict = {}

for i in lista:

    if i <= 0:
        continue

    if i in dict:
        continue
    else:
        dict[i] = i

        if result == 0:
            result = result +1

        if result < i: 
            continue

        result = result +1

        while result in dict:
            result = result +1

return result

测试用例:

lista = [5, 3, 4, -1, 1, 2]
lista = [1,2,3,4,5]
lista = [3, 4, -1, 1]
lista = [2, 3, 4, 1]
lista = [1,0]
lowest_positive(lista)

请注意,我不认为0是正数

逻辑:如果数字小于0,则将其拒绝。然后在字典中检查该数字是否存在,如果存在,则读取下一个数字,否则将其添加到字典中。结果是计数器被一一递增。如果结果小于列表中读取的数字,则读取下一个数字,否则,计数器加一,并且也在字典中检查此结果。全部字典将存储列表中读取的所有数字,以及列表中读取的最小数字之间的所有缺失正数。

答案 9 :(得分:0)

上述方法的缺点是分配“ max_value”会占用额外的空间,这不是正确的解决方案

def missing_positive_integer(my_list):
    max_value = max(my_list)
    my_list = [num for num in range(1,max(my_list)) if num not in my_list]
    if len(my_list) == 0:
        my_list.append(max_value+1)

    return min(my_list)

my_list = [1,2,3,4,5,8,-1,-12,-3,-4,-8]
missing_positive_integer(my_list)

答案 10 :(得分:0)

PMCarpan算法的JavaScript实现

function getMissingInt(array) {
  const segArray = array.filter((a) => a > 0);
  for (let i = 0; i < segArray.length; i++) {
    const value = Math.abs(segArray[i]);
    if (value <= segArray.length && segArray[value - 1] > 0) {
      segArray[value - 1] *= -1;
    }
  }
  for (let i = 0; i < segArray.length; i++) {
    if (segArray[i] > 0) {
      return i + 1;
    }
  }
  return segArray.length + 1;
}
console.log(getMissingInt([1, -1, -5, -3, 3, 4, 2, 8]));
console.log(getMissingInt([3, 4, -1, 1]));
console.log(getMissingInt([1, 2, 0]));

答案 11 :(得分:-1)

Python:

QMenu::item { padding: 4px 25px 4px 20px; }

答案 12 :(得分:-1)

我没有详细测试它,但是对于排序数组,这是我的处理方法,欢迎进行任何改进。 约束:

  • 线性时间
  • 恒定空间

    solution:
    start with lowest positive integer (i.e. lpi <- 1)
    while parsing the array, if lpi is already in the array, increment it
    

lpi现在是数组中不可用的最低正整数

简单的python函数如下:

def find_lpi(arr):
    lpi = 1
    for i in arr:
        if lpi == i:
            lpi += 1
    return lpi

如果数组未排序,则可以选择以下解决方案。

首先创建一个零长度为max(arr)的二进制数组X。     对于数组中的每个项目,将X的索引标记为1     返回最小索引为0

以下是一个令人满意的简单实现

  • 线性时间
  • 恒定空间复杂度约束。

    def find_lpi(arr):
        x = [0 for x in range(max(arr)+1)]
         for i in arr:
             x[i] = 1 
         for i in range(1,len(x)):
             if x[i] ==0:
                 return i
         return len(x)
    

答案 13 :(得分:-1)

public int FindMissing(){
    var list = new int[] { 6, -6, 4, 5 };
    list = list.OrderBy(x => x).ToArray();
    var maxValue = 0;
    for (int i = 0; i < list.Length; i++)
    {
        if (list[i] <= 0)
        {
            continue;
        }
        if (i == list.Length - 1 ||
            list[i] + 1 != list[i + 1])
        {
            maxValue = list[i] + 1;
            break;
        }
    }
    return maxValue;
}
  1. 按升序对数据进行排序:
  2. for循环数据
    • 如果值小于0,则不执行任何操作并跳过。
    • 检查当前索引值加1是否等于下一个索引值
      • 如果是,请继续循环。
      • 如果否,则当前索引值加1将是缺失的正整数