문제
N개의 수로 이루어진 수열 A[1], A[2], …, A[N]이 있다. 이 수열에 대해서 버블 소트를 수행할 때, Swap이 총 몇 번 발생하는지 알아내는 프로그램을 작성하시오.
버블 소트는 서로 인접해 있는 두 수를 바꿔가며 정렬하는 방법이다. 예를 들어 수열이 3 2 1 이었다고 하자. 이 경우에는 인접해 있는 3, 2가 바뀌어야 하므로 2 3 1 이 된다. 다음으로는 3, 1이 바뀌어야 하므로 2 1 3 이 된다. 다음에는 2, 1이 바뀌어야 하므로 1 2 3 이 된다. 그러면 더 이상 바꿔야 할 경우가 없으므로 정렬이 완료된다.
입력
첫째 줄에 N(1 ≤ N ≤ 500,000)이 주어진다. 다음 줄에는 N개의 정수로 A[1], A[2], …, A[N]이 주어진다. 각각의 A[i]는 0 ≤ |A[i]| ≤ 1,000,000,000의 범위에 들어있다.
출력
첫째 줄에 Swap 횟수를 출력한다
예제 입력 1
3
3 2 1
예제 출력 1
3
문제 풀이
해당 문제는 최대 배열의 길이가 500,000이므로 버블소트를 진행한다면 O(N^2)로 시간 초과가 나온다. 시간 초과를 피하기 위해 버블 솔트와 같이 스왑을 하지만 시간 복잡도가 낮은 병합 정령(merge sort)로 문제를 풀었다.
병합 정렬을 이용하여 nlogn으로 해결할 수 있다.
- 정렬된 LeftArray와 RightArray로 나누어서 LeftArray의 길이를 count에 넣고 정렬을 시작한다.
- 이제 LeftArray의 맨 앞단의 숫자와 RightArray의 맨 앞단 숫자를 비교한다.
- 이 과정에서 작은 숫자를 새로운 배열에 추가한다.
- 해당 숫자가 RightArray의 숫자라면 count를 SwapCount에 추가한다.
- 해당 숫자가 LeftArray의 숫자라면 count를 줄인다.
- 위 그림에서는 RightArray의 1을 삽입하고, count 3을 Swapcount에 추가한다.
- LeftArray 값이 작으므로 2를 넣고, LeftArray의 값이 들어가는 경우 Count를 1 줄인다.
- LeftArray 값이 작으므로 3을 넣고, Count를 줄인다.
- RightArray 값이 작으므로 4를 넣고, Swap에 Count를 더한다.
- 한쪽 배열이 비어있으면 다른 배열의 값을 그냥 넣는다.
위 병합 정렬을 사용하면 시간 초과 없이 스왑 횟수를 출력할 수 있다.
풀이 코드
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
public class Main {
public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static StringTokenizer st;
public static int INF = Integer.MAX_VALUE;
static long swapCount = 0;
static long[] sorted;
public static void main(String[] args) throws IOException {
int N = Integer.parseInt(br.readLine());
sorted = new long[N];
long[] arr = new long[N];
arr = Arrays.stream(br.readLine().split(" ")).mapToLong(Long::parseLong).toArray();
mergeSort(arr, 0,N-1);
System.out.println(swapCount);
}
static void mergeSort(long[] arr, int left, int right) {
if(left < right) {
int mid = (left + right) / 2;
mergeSort(arr,left,mid);
mergeSort(arr,mid+1,right);
merge(arr, left,right);
}
}
static void merge(long[] arr, int start, int end) {
int mid = (start+end) / 2;
int left = start;
int right = mid+1;
int index = start;
while(left <= mid && right <= end) {
if(arr[left] <= arr[right]) {
sorted[index++] = arr[left++];
}else {
sorted[index++] = arr[right++];
swapCount += mid + 1 - left;
}
}
while(left <= mid) {
sorted[index++] = arr[left++];
}
while(right <= end) {
sorted[index++] = arr[right++];
}
for(int i = start; i <= end; i++) {
arr[i] = sorted[i];
}
}
}
'algorithm > problems' 카테고리의 다른 글
[백준/Java] 17472: 다리 만들기 2 (0) | 2023.09.20 |
---|---|
[백준 / Java] 2110번: 공유기 설치 (0) | 2023.09.19 |
[백준 / Java] 1194번: 달이 차오른다, 가자. (0) | 2023.08.25 |
[백준 / Java] 2473번 : 세 용액 (0) | 2023.08.22 |
[백준 / Java] 2263번 : 트리의 순회 (0) | 2023.08.21 |