이진 탐색 문제풀이(feat: 세 수의 합 : 골드 )

성찬홍·2024년 10월 19일

자료구조

목록 보기
23/29
post-thumbnail

세 수의 합

https://www.acmicpc.net/problem/2295

문제

N(5 ≤ N ≤ 1,000)개의 자연수들로 이루어진 집합 U가 있다. 이 중에서 적당히 세 수를 골랐을 때, 그 세 수의 합 d도 U안에 포함되는 경우가 있을 수 있다. 이러한 경우들 중에서, 가장 큰 d를 찾으라.

예를 들어 {2, 3, 5, 10, 18}와 같은 집합이 있다고 하자. 2+3+5 = 10이 되고, 이 수는 집합에 포함된다. 하지만 3+5+10 = 18이 되고, 이 경우가 세 수의 합이 가장 커지는 경우이다.

입력

첫째 줄에 자연수 N이 주어진다. 다음 N개의 줄에 차례로 U의 원소가 하나씩 주어진다. 주어진 U는 집합이 되므로 입력되는 두 수가 같아서는 안 된다. U의 원소는 200,000,000보다 작거나 같은 자연수이다. 답이 항상 존재하는 경우만 입력으로 주어진다.

출력

우리가 x번째 수, y번째 수, z번째 수를 더해서 k번째 수를 만들었다라고 하자. 위의 예제에서 2+3+5=10의 경우는 x, y, z, k가 차례로 1, 2, 3, 4가 되며, 최적해의 경우는 2, 3, 4, 5가 된다. k번째 수가 최대가 되도록 하는 것이 목적이다. x, y, z, k가 서로 같아도 된다. 이때, k번째 수를 출력하면 된다.

문제 풀이

풀이 방향

  • 세 개의 숫자이므로 , 한 개의 숫자를 고정으로 잡는다.
  • 남은 2개의 숫자를 반복문을 2번 돌린다.
  • 이진 탐색을 통해 최대 숫자를 찾는다.
// 이진 탐색으로 개똥벌레
function solution3(N, array) {
  // 오름찬순 정렬
  array.sort((a, b) => a - b);

  let answer = 0;

  // 이진 탐색
  // 이진 탐색 함수
  function binary(arr, target, left, right) {
    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      if (arr[mid] === target) {
        return true;
      } else if (arr[mid] < target) {
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }
    return false; // target이 없는 경우
  }

  // 세개의 수를 비교해야하므로 이진 탐색을 두번
  for (let i = array.length - 1; i >= 0; i--) {
    // 가장 큰 수 MaxNum을 고정
    const MaxNum = array[i];

    // 두 수의 합을 계산
    for (let j = 0; j < array.length; j++) {
      for (let k = j + 1; k < array.length; k++) {
        // 두 수의 합 계산
        let sum = array[j] + array[k];

        if (sum >= MaxNum) {
          break; // 두 수의 합이 MaxNum을 넘으면 의미 없으므로 종료
        }

        // 이진 탐색으로 나머지 값 확인
        if (binary(array, MaxNum - sum, k + 1, array.length - 1)) {
          answer = Math.max(answer, MaxNum);
        }
      }
    }
  }
  return answer;
}

console.log(solution3(5, [2, 3, 5, 10, 18]));

정리

  • 이번 문제는 조금 꼬아져 있었지만, 특별한 조건은 없이 이진 탐색을 여러번 돌리는 것으로 해결할 수 있었습니다.
  • 이진 탐색에 좀 더 익숙히 사용할 수 있었습니다.
profile
꾸준한 개발자

0개의 댓글