길이가 같은 두 개의 큐가 주어진다. 하나의 큐를 골라서 원소를 추출하고 추출된 원소를 다른 큐에 집어넣는 작업을 통해서 각 큐의 원소 합이 같도록 만든다.
이때 필요한 최소 작업 수를 반환하면 된다. pop - insert 쌍이 1회 수행으로 간주된다.
길이가 같은 두 개의 큐를 나타내는 정수 배열
queue1
,queue2
가 매개변수로 주어집니다. 각 큐의 원소 합을 같게 만들기 위해 필요한 작업의 최소 횟수를 return한다.
단, 어떤 방법으로도 합을 같게 만들지 못하면 -1을 return 한다.
queue2
에서 원소를 하나 꺼내 queue1
에 추가하고, 크다면, queue1
에서 원소를 하나 꺼내 queue2
에 추가한다.여기서 가능한 최대 이동 횟수는 무한 루프를 방지하기 위해 상한 값으로 설정한 것입니다.
큐의 길이가 고정되어 있고 두 큐를 순환하기 때문에 최악의 경우 두 큐 간에 한 번씩 모두 이동하기 때문에 이동 연산이 발생합니다.
만약, 한 큐에서 다른 큐로 이동했는데 다시 원소를 되돌려야하는 상황이 발생했을 경우도 고려하면 3번 반복되기 때문에 최대 이동 횟수를(두 큐의 길이 * 3)
을 상한값으로 설정했습니다.
import java.util.*;
class Solution {
public int solution(int[] queue1, int[] queue2) {
Queue<Integer> q1 = new LinkedList<>();
Queue<Integer> q2 = new LinkedList<>();
long sum1 = 0, sum2 = 0;
for (int num : queue1) {
q1.offer(num);
sum1 += num;
}
for (int num : queue2) {
q2.offer(num);
sum2 += num;
}
long totalSum = sum1 + sum2;
if (totalSum % 2 != 0) {
return -1;
}
long target = totalSum / 2;
int moveCount = 0, maxMoves = 3 * (queue1.length + queue2.length);
while (moveCount <= maxMoves) {
if (sum1 == target) {
return moveCount;
}
if (sum1 < target) {
int value = q2.poll();
q1.offer(value);
sum1 += value;
sum2 -= value;
} else {
int value = q1.poll();
q2.offer(value);
sum1 -= value;
sum2 += value;
}
moveCount++;
}
return -1;
}
}
다른 사람들의 풀이를 보니 큐를 사용하지 않고 하나의 배열을 사용한 풀이가 많았다. 그래서 배열을 사용해 풀이를 해보았다.
public int solution(int[] queue1, int[] queue2) {
long sum1 = Arrays.stream(queue1).asLongStream().sum();
long sum2 = Arrays.stream(queue2).asLongStream().sum();
long totalSum = sum1 + sum2; // 두 큐의 합 (전체 배열 합)
// 전체 합이 홀수면 두 큐를 동일하게 나눌 수 없음.
if (totalSum % 2 != 0) return -1;
long target = totalSum / 2; // 목표 합
// 두 배열을 하나로 결합
int[] merged = new int[queue1.length + queue2.length];
System.arraycopy(queue1, 0, merged, 0, queue1.length);
System.arraycopy(queue2, 0, merged, queue1.length, queue2.length);
// 투 포인터 설정
int start = 0, end = queue1.length; // start는 첫 번째 큐의 시작점, end는 두 번째 큐의 시작점
long current = sum1; // 현재 첫 번째 큐의 합으로 초기화
int moveCount = 0; // 이동 횟수
int maxMoves = 3 * merged.length;
// 투 포인터를 활용하여 목표 합에 도달할 때까지 반복
while (moveCount <= maxMoves) {
if (current == target) return moveCount; // 목표 합에 도달하면 이동 횟수 반환
// 현재 합이 목표보다 작은 경우: 큐2에서 큐1로 원소를 추가
if (current < target) {
current += merged[end % merged.length]; // end가 가리키는 값을 더함
end++; // end 포인터를 오른쪽으로 이동
}
// 현재 합이 목표보다 큰 경우: 큐1에서 원소를 제거
else {
current -= merged[start % merged.length]; // start가 가리키는 값을 뺌
start++; // start 포인터를 오른쪽으로 이동
}
moveCount++; // 이동 횟수 증가
}
// 반복이 끝났음에도 목표를 달성하지 못한 경우, -1 반환
return -1;
}
위의 큐를 이용한 풀이와 배열을 이용한 풀이 중 큐를 이용하는게 더 직관적이라 이해하기 쉬운 것 같다.