web-dev-qa-db-ja.com

整数の配列が与えられた場合、線形時間および定数空間で最初に欠落している正の整数を見つけます

つまり、配列に存在しない最小の正の整数を見つけます。配列には、重複と負の数も含めることができます。この質問は、プログラミングのインタビューで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;
}

ここでは、まず配列を並べ替えてから、配列を1回走査します。配列を走査する前に、 "min"という名前の変数を1に初期化しました。今度は、配列を走査しているときに、minに等しい整数を取得したら、単純にminの値を増やします。これにより、min変数には、まだ発生していない最新の最小の正の整数が保持されます。より良いアプローチを考えられますか?前もって感謝します。

8
Jhanak Didwania

配列を変更できると仮定すると、

  1. 最初の部分が正数のみで構成されるように、配列を2つの部分に分割します。開始インデックスが_0_であり、終了インデックスがend(exclusive)であるとします。

  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+1_が配列内にある場合、インデックスiを持つ要素の値を負に変更します。

_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
_
11
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:]部分は、説明に基づいて開始点としてゼロを含めていないためです。

1
FredMan

これが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
*/
0
Rishabh Jain

リストがインプレースで変更可能であると仮定します。
アイデア:リスト値(範囲内)を使用して、リストのインデックスに自己「タグ付け」します。この「タグ付き」リストの最小のタグなしインデックスを返します。
例:リストが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
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. データをループします
    • 値が0より小さい場合、何もせずにスキップします。
    • 現在のインデックス値に1を加えた値が次のインデックス値と等しいかどうかを確認します
      • はいの場合、ループを続行します。
      • いいえの場合、現在のインデックス値に1を加えた値が欠落した正の整数になります
0
Kaihao Phang
#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))
0
danish_imam

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
0
rrawat

はるかに簡単です。 (解決策は私のものではありません)

public static int Missing(int[] a)
{
    // the idea is to put all values in array on their ordered place if possible
    for (int i = 0; i < a.Length; i++)
    {
        CheckArrayAtPosition(a, i);
    }

    for (int i = 0; i < a.Length; i++)
        if (a[i] != i + 1)
            return i + 1;
    return a.Length + 1;
}

private static void CheckArrayAtPosition(int[] a, int i)
{
    var currentValue = a[i];
    if (currentValue < 1) return; // do not touch negative values because array indexes are non-negative
    if (currentValue > a.Length) return; // do not touch values that are bigger than array length because we will not locate them anyway
    if (a[currentValue - 1] == currentValue) return; // do not need to change anything because index contain correct value already
    Swap(a, i, currentValue - 1);
    CheckArrayAtPosition(a, i); // now current position value is updated so we need to check current position again
}

private static void Swap(int[] a, int i, int j)
{
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

再帰がありますが、各スワップは1つの値を正しい場所に置くため、<= nのスワップがあります。線形時間

0
Anubis