Algorithm/LeetCode

[LeetCode 27] Remove Element - TypeScript 문제 풀이 및 최적화

쪽제비 2025. 3. 3. 07:30

[LeetCode] Remove Element - TypeScript 문제 풀이 및 최적화

문제 설명

LeetCode의 "Remove Element" 문제는 배열 nums에서 특정 값 val을 제거하고, 남은 요소의 개수를 반환하는 문제입니다.

배열을 직접 수정해야 하며, 순서는 바뀌어도 무관합니다. 반환값으로는 유효한 길이를 제공합니다.


문제를 처음 접했을 때 어려웠던 점

처음에는 단순히 val을 제거하는 문제라고 생각했는데, 실제로는 맨 끝 요소와 바꿔가면서 해결해야 하는 문제였습니다. 처음 문제를 풀 때는 배열에서 val을 그냥 지우려고 했지만, 삭제하는 방식으로는 올바르게 해결되지 않았습니다.

배열의 순서를 유지할 필요가 없기 때문에 맨 끝 요소와 교환하며 해결하는 방식을 이해하는 것이 핵심이었습니다.


최적화된 TypeScript 풀이

문제를 올바르게 해결하기 위해 두 개의 포인터를 사용하여 val을 배열의 끝으로 보내는 방식으로 구현했습니다.

export function removeElement(nums: number[], val: number): number {
  let right = nums.length - 1;
  let index = 0;

  while (index <= right) {
    if (nums[index] === val) {
      nums[index] = nums[right]; // `right`의 값을 `index`에 덮어쓰기
      right--; // right를 줄여 제거한 효과
    } else {
      index++; // val이 아닐 때만 index 증가
    }
  }

  return right + 1; // 유효한 길이 반환
}

코드의 핵심 개념

배열의 순서를 유지할 필요가 없으므로, 뒤쪽 요소와 교환 가능
앞에서부터 순회하며 val을 만나면 맨 끝 요소와 교환
반환값은 유효한 요소 개수 (right + 1)


Jest 테스트 코드

코드의 정확성을 검증하기 위해 Jest 테스트 코드를 작성했습니다.

describe("LeetCode 27: Remove Element", () => {
  it("removes all instances of 3", () => {
    const input = [3,2,2,3];
    const result = removeElement(input, 3);
    expect(result).toEqual(2);
    expect(input.slice(0, result).sort()).toEqual([2, 2]);
  });

  it("removes all instances of 2", () => {
    const input = [0,1,2,2,3,0,4,2];
    const result = removeElement(input, 2);
    expect(result).toEqual(5);
    expect(input.slice(0, result).sort()).toEqual([0, 0, 1, 3, 4]);
  });

  it("handles an array with no occurrences", () => {
    const input = [1, 3, 5, 7];
    const result = removeElement(input, 2);
    expect(result).toEqual(4);
    expect(input.slice(0, result)).toEqual([1, 3, 5, 7]);
  });

  it("handles an empty array", () => {
    const input: number[] = [];
    const result = removeElement(input, 1);
    expect(result).toEqual(0);
    expect(input).toEqual([]);
  });
});

다양한 테스트 케이스 추가 → 엣지 케이스(빈 배열, 없는 값 등)까지 검증
배열의 순서가 바뀌어도 정답이므로 sort()로 정렬하여 검증
result를 활용한 직관적인 검증 → input.slice(0, result)로 올바른 요소 확인


결론

처음에는 val을 배열에서 단순히 제거하는 문제라고 생각했지만, 실제로는 맨 끝 요소와 바꾸면서 해결하는 문제였습니다. 이 점을 이해하는 것이 가장 어려웠고, 이후에는 두 개의 포인터를 활용하여 깔끔하게 해결할 수 있었습니다.

이제 TypeScript 알고리즘 문제 풀이를 더 효율적으로 작성하는 방법을 배웠습니다! 🚀