codingtest

두 큐 합 같게 만들기

2026-08-06
2분 분량
JAVA프로그래머스

문제 링크

문제 요약

  • 길이가 같은 두 큐 queue1, queue2가 주어진다
  • 한 큐에서 원소를 꺼내(pop) 다른 큐에 넣는(insert) 것을 합쳐 작업 1회로 센다
  • 이 작업을 반복해서 두 큐의 원소 합을 같게 만드는 최소 횟수를 구한다
  • 불가능하면 -1을 반환한다
  • 큐 길이는 최대 300,000, 원소는 최대 10^9라 합 계산에 long을 써야 한다

문제 풀이

처음에는 두 큐 중 아무 쪽에서나 원소를 하나씩 옮겨보면서 합이 같아지는 조합을 찾으면 되지 않을까 생각했다.

즉 매 단계마다 어느 큐에서 옮길지 모든 경우를 다 시도해보는 방식이다.

하지만 이 방식은 말이 안 된다.

큐의 길이가 각각 최대 300,000이라 두 큐를 합치면 원소가 최대 60만 개다.

매 단계 옮길 큐를 선택하는 경우의 수를 전부 따지면 경우의 수가 기하급수적으로 늘어나서 시간 안에 절대 끝나지 않는다.

이 문제의 핵심은 합이 더 큰 큐의 맨 앞 원소를 합이 더 작은 큐로 옮기는 것이 항상 최적이라는 점이다.

  • 큐는 순서를 유지해야 하므로 옮길 수 있는 원소는 항상 맨 앞뿐이다
  • 그렇다면 남은 선택은 "어느 큐에서 옮길 것인가" 뿐인데, 합이 큰 쪽에서 작은 쪽으로 옮기지 않으면 격차가 줄지 않는다
  • 그래서 두 합을 계속 추적하면서, 매 단계 합이 큰 큐의 앞 원소를 반대편으로 옮기는 그리디로 풀었다

전체 합이 홀수면 애초에 반으로 나눌 수 없으므로 바로 -1을 반환한다.

이때 중요한 점은, 큐가 순환하듯 계속 돌기 때문에 시도 횟수를 제한하지 않으면 무한 루프에 빠질 수 있다는 것이다.

그래서 두 큐 길이 합의 두 배만큼 시도해도 합이 같아지지 않으면 -1로 판단하고 끝낸다.

최종 코드

java
import java.util.*;

class Solution {
    public int solution(int[] queue1, int[] queue2) {
        long sum1 = 0; // 오버플로우 방지를 위해 long으로 큐1의 합을 관리
        long sum2 = 0; // 큐2의 합
        
        Deque<Integer> q1 = new ArrayDeque<>(); // 맨 앞에서 꺼내고 맨 뒤로 넣는 큐 구조
        Deque<Integer> q2 = new ArrayDeque<>();
        
        for(int num : queue1){
            sum1+=num;
            q1.offerLast(num);
        }
        for(int num : queue2){
            sum2+=num;
            q2.offerLast(num);
        }
        
        // 전체 합이 홀수면 두 큐를 같은 값으로 나눌 수 없으므로 바로 종료
        if ((sum1 + sum2) % 2 != 0) {
            return -1;
        }
        
        int idx = (queue1.length + queue2.length)*2; // 무한 루프를 막기 위한 시도 횟수 상한
        for(int i=0;i<=idx;i++){
            if(sum1 == sum2){
                return i; // 두 합이 같아지는 순간까지의 작업 횟수를 반환
            }
            
            if(sum1 < sum2){
                // 합이 작은 q1 쪽으로 q2의 맨 앞 원소를 옮긴다
                int num = q2.pollFirst();
                q1.offerLast(num);
                sum1 += num;
                sum2 -= num;
                continue;
            }
            
            if(sum1 > sum2){
                // 반대로 합이 큰 q1에서 q2로 맨 앞 원소를 옮긴다
                int num = q1.pollFirst();
                q2.offerLast(num);
                sum1 -= num;
                sum2 += num;
            }
        }
        
        return -1;
    }
}

함께 읽으면 좋은 글

코딩 테스트2026-08-23

택배상자

order 배열은 택배 기사님이 원하는 상자 적재 순서다 기존 컨테이너 벨트는 1번부터 순서대로만 꺼낼 수 있다 보조 벨트는 스택처럼 마지막에 넣은 것부터 꺼낼 수 있다 원하는 순서대로 최대한 실을 수 있는 상자 개수를 구하는 문제다 처음에는 기존 벨트를 실제 리스트로 만들어…

코딩 테스트2026-08-23

롤케이크 자르기

topping 배열은 롤케이크에 일렬로 올라간 토핑 번호다 한 지점을 잘라 두 조각으로 나눴을 때, 양쪽 토핑 종류 수가 같아야 공평하게 나눈 것이다 공평하게 자를 수 있는 방법의 수를 구하는 문제다 처음에는 자르는 위치마다 왼쪽과 오른쪽 배열을 나눠서 각각 서로 다른 토핑…

코딩 테스트2026-08-23

할인 행사

want, number 배열로 정현이가 원하는 제품과 수량을 표현한다 discount 배열은 XYZ 마트가 매일 할인하는 제품 목록이다 연속된 10일 동안 할인 제품 종류와 수량이 want, number와 정확히 일치해야 회원가입할 수 있다 그런 시작일이 총 몇 번 있는지…

코딩 테스트2026-08-23

숫자 변환하기

자연수 x를 y로 바꾸는 데 x+n, x2, x3 세 가지 연산을 쓸 수 있다 x를 y로 바꾸는 최소 연산 횟수를 구하는 문제다 만들 수 없으면 -1을 반환한다 처음에는 x에서 시작해서 세 가지 연산을 재귀적으로 다 시도해보고 y에 도달하는 경로 중 가장 짧은 걸 고르면…