문제
- 링크
- 정렬되지 않은
nums 배열이 주어진다. 이 배열에 포함되지 않으면서 가장 작은 자연수를 구해야한다. 시간 복잡도는 O(n)이고 추가적인 공간 복잡도는 O(1)이어야 한다.
- 제약 조건
- 배열 길이:
1 <= nums.length <= 10^5
- 값 범위:
-2^31 <= nums[i] <= 2^31 - 1
풀이
풀기 전
- 아이디어가 안 떠올라서 discussion을 참고했다.
- 핵심 아이디어는 배열 길이를 n이라고 할 때, 정답의 범위가
[1, n+1]이라는 거다. 만약 nums = [1, 2, 3, ... n-1, n]이라면 정답은 n+1이다. 하지만 값이 하나라도 바뀌면 정답의 범위는 [1, n]이 된다. 특정 자연수 값이 비어버리기 때문이다.
- 그래서
nums를 순회하면서 [1, n]에 방문 체크를 한 뒤에, 방문되지 않은 값이 있으면 반환하면 된다. 또는 모두 방문됐으면 n+1을 반환하면 된다. 그런데 추가적인 공간 복잡도가 상수 시간이어야 하므로, set을 따로 만들 순 없다. 그렇다면 주어진 nums를 사용해서 방문 체크를 해줄 수 있겠다.
코드
class Solution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;
for (int i=0; i<n; i++) {
if (nums[i] < 0 || nums[i] > n)
nums[i] = 0;
}
for (int i=0; i<n; i++) {
if (nums[i] == n+1)
continue;
int num = nums[i];
int next_idx;
while (num > 0 && num <= n) {
next_idx = num - 1;
num = nums[next_idx];
nums[next_idx] = n + 1;
}
}
for (int i=0; i<n; i++) {
if (nums[i] != n + 1)
return i + 1;
}
return n + 1;
}
}
푼 후
- 어려웠다.
- 방문 체크를 해줘야 할 거 같은데 정답의 범위가
[1, n+1]인 것을 알아채지 못해서 헤맸다. 정답 범위를 제한적이라는 걸 떠올린다면 주어진 nums로 방문 체크 한다는 생각까지 자연스럽게 이어질 수 있을 거 같다.