투 포인터를 이용해 조건을 만족시키는 두 숫자 가져오기

백준 2470번

QUESTION LINK

주어진 숫자들 중 합이 0에 가깝도록 만들 수 있는 두 숫자를 찾는 문제였습니다. 투 포인터를 이용해서 풀어야하는 문제였고, 해당 문제를 풀기 위한 순서는 아래와 같습니다.

  1. 주어진 숫자들을 오름차순으로 정렬하기 (-98, -15, 0, 1, 22)
  2. 정렬된 숫자들의 왼쪽, 오른쪽에 각각 포인터를 두기
  3. 각 포인터에 해당하는 값들의 합을 구하고, 현재 갖고 있는 최소값과 비교하기
  4. 구해진 합이 최소값보다 큰 경우, 해당 포인터의 값과 최소값 저장하기
  5. 구해진 합이 0보다 큰 경우(우측 포인터 값이 좌측 포인터 값보다 큰 경우), 좌측 포인터를 한 칸 내리기
  6. 구해진 합이 0보다 작은 경우(좌측 포인터 값이 우측 포인터 값보다 큰 경우), 우측 포인터를 한 칸 올리기
  7. 우측 포인터와 좌측 포인터가 만나기 전까지 위 과정을 반복하기

위의 과정을 코드로 표현하면 아래와 같은 형태가 나오게 됩니다.

const [count, values] = fs.readFileSync(filePath).toString().trim().split("\n");
const sortedValues = values
  .split(" ")
  .map(Number)
  .sort((a, b) => a - b);
// 주어진 값들을 숫자로 만들고, 그 숫자들을 오름차순으로 정렬함

let results;
// 결과를 담을 변수
let start = 0;
// 왼쪽 포인터의 index값으로, 처음에 0으로 시작함
let end = sortedValues.length - 1;
// 오른쪽 포인터의 index값으로, 처음에 배열의 마지막부터 시작함
let min;
// 포인터의 합 중 최소값일 경우 해당 변수에 담음
let isEnd = false;
// true일 시 반복문 종료

while (!isEnd) {
  const sum = sortedValues[start] + sortedValues[end];
  if (!min || min > Math.abs(sum)) {
    // 현재의 합이 최소값보다 작은 경우, 최소값과 결과값을 변경함
    min = Math.abs(sum);
    results = [sortedValues[start], sortedValues[end]];
  }
  // 0보다 작을 시 왼쪽 포인터를 한 칸 올리고, 0보다 클 시 오른쪽 포인터를 한 칸 내림
  if (sum < 0) {
    start += 1;
  } else if (sum > 0) {
    end -= 1;
  } else {
    isEnd = true;
  }

  if (start === end) isEnd = true;
}

const result = results.join(" ");

console.log(result);

해당 문제는 투 포인터를 이용해서 풀 수 있는 대표적인 문제였습니다. 하지만, 처음에 문제를 풀 때 포인터를 이동하기 위한 조건(합이 0보다 크거나 작을 때 해당 포인터 이동)을 제대로 설정하지 못했고, 이로 인해 허비된 시간이 많았습니다. 투 포인터를 사용하며 기본적으로 이동시키기 위한 조건이 올바르게 설정되도록 유의해야 합니다.