/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
// 최대 2개까지 중복값 허용
// 배열을 다른 변수 공간에 추가로 할당할 수 없음.
for(let i = 0; i < nums.length; i++){
const firstIndex = nums.indexOf(nums[i]);
const lastIndex = nums.lastIndexOf(nums[i]);
// 중복이 없는 경우
if(lastIndex === firstIndex){
continue;
}
// 중복이 있으나 2개인 경우
if(lastIndex - firstIndex === 1){
// 다음 값도 어차피 같은 값이므로 i를 증가시킨다.
// 또한, continue를 통해 다음 i로 넘어가면서, 다음 i는 2가 증가된 값이 되며
// 2번째 중복값을 넘어감과 동시에 다음 숫자부터 시작 가능.
i++;
continue;
}
// 3개 이상 중복이 있는 경우
if(lastIndex - firstIndex >= 2){
nums.splice(firstIndex + 2, lastIndex - (firstIndex + 1));
i++;
}
}
// 최대 2개까지 중복을 허용했을 때, 그 이상의 중복을 제거한 배열의 길이를 반환
return nums.length;
};
nums 배열을 순회하면서 최대 2번만 중복되도록 하는 문제이다.
이 말은 즉, 2개까지는 중복이 허용이 된다는 뜻이다.
firstIndex와 lastIndex를 구한 뒤,
두 값이 같으면 중복이 아예 없는 것이고, 두 값의 차이가 1이면 같은 값이 2개라는 뜻이므로,
이 두 조건에 대해서는 연산을 하지않고 continue를 통해 다음으로 넘어간다.
추가로, 차이가 1일 때는 i를 증가시키는 연산을 추가해줘서 중복되는 값을 다시 한번 반복하는 일이 없도록 해주었다.
주요 연산이 필요한 곳은 3개 이상이 중복되는 경우이다.
만약 5개가 중복된다고 해보자.
ex) 배열 값으로 보는 예
[1,1,1,1,1] => [1,1]
ex) 위 예시를 인덱스로 보는 경우(보편적인 예)
[firstIndex, firstIndex + 1, firstIndex + 2, firstIndex + 3, lastIndex]
=> [firstIndex, firstIndex + 1]
즉, 3번째 값부터 끝까지는 전부 지워야할 대상이 된다.
인덱스로 정확히 표현해보자면, firstIndex + 2부터 lastIndex까지가 대상이다.
이를 표현한 것이 바로 아래 공식이다.
nums.splice(firstIndex + 2, lastIndex - (firstIndex + 1));
splice()를 통해 firstIndex + 2부터 lastIndex까지 지우는 것이다.
그런데 splice()의 두 번째 인자로는 인덱스 번호가 아니라 몇 개를 지울지를 줘야하기 때문에
추가적인 연산을 해줬다.
필자는 시간 복잡도의 경우 98%까지는 달성했지만, 메모리 쪽에서는 성능이 낮았다.
다른 분의 풀이를 가져왔는데 이 분은 메모리 쪽도 잘 잡으신듯 하다.
이 방법도 two pointer가 아닌가싶다.
var removeDuplicates = function(nums) {
if(nums.length <= 2) {
return nums.length;
}
let k = 2;
for(let i = 2; i < nums.length; i++){
if(nums[i] != nums[k - 2] || nums[i] != nums[k - 1]){
nums[k] = nums[i];
k++;
}
}
return k;
};
우선 2개 이하일 때에 대한 예외 처리를 해준 것을 확인할 수 있다.
논리에 대한 부분은 필자와 같다.
다만, k를 기준으로 두고 i가 증가하는 for문과 대조하여 k를 증가시키는 방법을 사용한다.
또한, 필자와 반대로 연속되지 않는 원소(중복이 없는 원소)에 대하여 카운트를 해주는 듯하다.
필자가 for문에서 한 번의 순회마다 인덱스 서칭을 위해 두 개의 상수를 만들어내는 반면,
이 분은 그 변수, 상수 할당이 정말 적고 순회마다 할당되는 것도 아니기 때문에
좋은 공간 복잡도(메모리)가 나온게 아닐까 싶다.