다음 O(N)
은 O(N)
공간 을 사용 하는 간단한 솔루션입니다 . 입력 목록을 음수가 아닌 숫자로 제한하고 목록에없는 첫 번째 음이 아닌 숫자를 찾고 싶다고 가정합니다.
- 목록의 길이를 찾으십시오. 그것은이라고 말할 수 있습니다
N
.
N
all로 초기화 된 부울 배열을 할당 합니다 false
.
X
목록의 각 숫자 에 대해 X
보다 작은 경우 배열 N
의 X'th
요소를로 설정합니다 true
.
- index
0
에서 시작하는 배열을 스캔하여 인 첫 번째 요소를 찾습니다 false
. 첫 번째 발견하면 false
인덱스를 I
, 다음 I
답변입니다. 그렇지 않으면 (즉, 모든 요소가있을 때 true
) 대답은 N
입니다.
실제로 " N
부울 배열 "은 byte
또는 int
배열 로 표시되는 "비트 맵"또는 "비트 세트"로 인코딩 될 수 있습니다 . 이것은 일반적으로 더 적은 공간 (프로그래밍 언어에 따라 다름)을 사용하고 첫 번째 스캔이 false
더 빨리 수행되도록합니다.
이것이 알고리즘이 작동하는 방법 / 이유입니다.
N
목록 의 숫자가 구별되지 않거나 그 중 하나 이상이보다 크다고 가정 N
합니다. 이는 목록에없는 범위에 숫자가 하나 이상 있어야 함을 의미 0 .. N - 1
합니다. 따라서 가장 작은 결측 수를 찾는 문제는 따라서 보다N
작은 결측 수를 찾는 문제로 축소되어야합니다 . 이것은 N
... 보다 크거나 같은 숫자를 추적 할 필요가 없다는 것을 의미합니다 . 왜냐하면 그들은 답이 될 수 없기 때문입니다.
이전 단락의 대안은 목록이에서 번호의 순열이라는 것입니다 0 .. N - 1
. 이 경우 3 단계에서는 배열의 모든 요소를로 설정하고 true
4 단계에서는 첫 번째 "누락 된"숫자가 N
입니다.
알고리즘의 계산 복잡성은 O(N)
상대적으로 작은 비례 상수를 갖습니다. 목록을 두 번의 선형 전달하거나 목록 길이가 시작하는 것으로 알려진 경우 한 번만 전달합니다. 전체 목록을 메모리에 저장할 필요가 없습니다. 따라서 알고리즘의 점근 적 메모리 사용량은 부울 배열을 나타내는 데 필요한 것입니다. 즉 O(N)
비트.
(반대로, 메모리 내 정렬 또는 분할에 의존하는 알고리즘은 전체 목록을 메모리에 표시 할 수 있다고 가정합니다. 질문 형식에서는 O(N)
64 비트 단어 가 필요합니다 .)
1 ~ 3 단계의 @Jorn 주석은 계산 정렬의 변형입니다. 어떤 의미에서 그는 옳지 만 차이점은 중요합니다.
- 계수 정렬에는 목록에서 가장 큰 숫자이고 목록 에서 가장 작은 숫자 인 (적어도)
Xmax - Xmin
카운터 배열이 필요 합니다. 각 카운터는 N 개의 상태를 나타낼 수 있어야합니다. 즉, 이진 표현을 가정하면 정수 유형 (적어도) 비트 가 있어야 합니다.Xmax
Xmin
ceiling(log2(N))
- 배열 크기를 결정하려면 계수 정렬을 통해 목록을 처음으로 통과하여
Xmax
및 을 결정해야합니다 Xmin
.
- 따라서 최소 최악의 경우 공간 요구 사항은
ceiling(log2(N)) * (Xmax - Xmin)
비트입니다.
대조적으로, 위에 제시된 알고리즘은 단순히 N
최악의 경우와 최상의 경우의 비트를 필요로합니다 .
그러나이 분석은 알고리즘이 목록을 처음으로 통과하여 0을 찾고 (필요한 경우 목록 요소를 세는 경우) 0을 찾으면 공백을 사용하지 않고 더 빠른 응답을 제공한다는 직관으로 이어집니다. 목록에서 하나 이상의 0을 찾을 가능성이 높은 경우이 작업을 수행 할 가치가 있습니다. 그리고이 추가 패스는 전반적인 복잡성을 변경하지 않습니다.
편집 : 사람들이 비트와 비트 맵을 사용하는 내 원래 설명이 혼란스러워 보이기 때문에 "부울 배열"을 사용하도록 알고리즘 설명을 변경했습니다.