[백준/JAVA] 1517번: 버블 소트
🔺 문제
1517번: 버블 소트
첫째 줄에 N(1 ≤ N ≤ 500,000)이 주어진다. 다음 줄에는 N개의 정수로 A[1], A[2], …, A[N]이 주어진다. 각각의 A[i]는 0 ≤ |A[i]| ≤ 1,000,000,000의 범위에 들어있다.
www.acmicpc.net
🔺 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
import java.util.*;
import java.io.*;
public class Main {
static long[] A, tmp;
static long result;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
A = new long[N + 1];
tmp = new long[N + 1];
StringTokenizer st = new StringTokenizer(br.readLine()," ");
for(int i = 1 ; i <= N ; i++) {
A[i] = Integer.parseInt(st.nextToken());
}
result = 0;
merge_sort(1, N); // 병합 정렬
System.out.println(result);
}
public static void merge_sort(int s, int e) {
if(e - s < 1)
return;
int mid = s + (e - s) / 2;
merge_sort(s, mid);
merge_sort(mid + 1 , e);
// tmp 배열 저장
for(int i = s ; i <= e ; i++) {
tmp[i] = A[i];
}
// 두 그룹 병합
int tmpIdx = s; // 현재 복사 위치
int idx1 = s;
int idx2 = mid + 1;
while(idx1 <= mid && idx2 <= e) {
if(tmp[idx1] > tmp[idx2]) { // 뒤쪽 데이터 값이 작은 경우 업데이트
A[tmpIdx] = tmp[idx2];
result += idx2 - tmpIdx; // 🔔 업데이트
tmpIdx++;
idx2++;
}
else {
A[tmpIdx++] = tmp[idx1++];
}
}
// 부분이 남은 경우
while(idx1 <= mid) {
A[tmpIdx++] = tmp[idx1++];
}
while(idx2 <= e) {
A[tmpIdx++] = tmp[idx2++];
}
}
}
|
cs |
✅ 해결 아이디어
- O(nlogn)의 시간 복잡도로 정렬 수행
- 병합 정렬 : 분할 → 정렬 → 합병.
💥 유의사항
두 그룹 병합하는 로직의 첫 번째 while문 안의 if문에서 tmp[idx1] > tmp[mid]
이 먼저 나와야한다....
별 생각 없이 두개 순서 바꿔서 작성해봤었는데 안 그러면 67%에서 자꾸 틀림,,,,
사유는 아래와 같음,,
🔺 다른 풀이들
- 정렬 메소드와 합병 메소드를 따로 두심.
백준 1517번. 버블 소트 (Java)
문제 링크 : https://www.acmicpc.net/problem/1517 문제 이름은 버블소트지만 버블소트로 풀면 틀리는 문제입니다. N이 최대 500,000 이죠 O(n^2)을 돌리면 당연하게도 시간초과가 납니다. 우리가 구해야 하는
bcp0109.tistory.com
- 복습용..
백준 1517번: 버블 소트 [분할정복][재귀] - Java
www.acmicpc.net/problem/1517 1517번: 버블 소트 첫째 줄에 N(1≤N≤500,000)이 주어진다. 다음 줄에는 N개의 정수로 A[1], A[2], …, A[N]이 주어진다. 각각의 A[i]는 0≤|A[i]|≤1,000,000,000의 범위에 들어있다. www.acmi
cceeun.tistory.com
- 신기방기...
[백준 1517] 버블 소트 (JAVA)
https://www.acmicpc.net/problem/1517버블 정렬을 이용하면 N^2으로 시간초과가 발생합니다. 병합 정렬을 이용하여 해결할 수 있습니다.병합 정렬을 진행하면서 두 개의 배열을 병합할 때 Swap 횟수를 계산
velog.io
💬 느낀 점
병합 정렬,,,,, 마스터하고 말거다...
1회독 | 2회독 | 3회독 | 4회독 | 5회독 |
V | 6/14 |
( + 6/14 2회독)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
import java.util.*;
import java.io.*;
public class Main {
static long[] A, tmp;
static long cnt;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
A = new long[N + 1];
tmp = new long[N + 1]; // 임시 저장 배열
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
for(int i = 1 ; i <= N ; i++) {
A[i] = Long.parseLong(st.nextToken());
}
cnt = 0;
merge_sort(1, N);
System.out.println(cnt);
}
// 1. 분할
private static void merge_sort(int s, int e) {
if(s < e) {
int mid = s + (e - s) / 2;
merge_sort(s, mid);
merge_sort(mid + 1, e);
merge(s, mid, e);
}
}
// 2. 정복
private static void merge(int s, int m, int e) {
// 정렬이 필요한 배열을 필요한 만큼 "매번" 복사
for(int i = s ; i <= e ; i++) {
tmp[i] = A[i];
}
// 두 그룹 병합 로직
int l = s;
int r = m + 1;
int idx = s; // 현재 복사 위치
while(l <= m && r <= e) {
if(tmp[l] <= tmp[r]) {
A[idx] = tmp[l];
l++;
} else { // 뒤쪽 데이터 값이 작은 경우 swap 발생했으므로 cnt 업데이트
A[idx] = tmp[r];
cnt += (m + 1 - l); // 🔔 앞쪽 배열의 남은 데이터 개수만큼 더함
r++;
}
idx++;
}
// 앞쪽 배열에 데이터 남아있는 경우, 배열 끝에서 남은만큼을 돌면서 값 채우기
// (뒷 부분에 남은 거는 상관 없음)
while(l <= m) {
A[idx++] = tmp[l++];
}
// while(r <= e) {
// A[idx++] = tmp[r++];
// }
}
}
|
cs |
두 번째 본다고 좀 알 것 같다..만
혼자서 구현은 못 했다. (분발하자!!!)
암튼 이번에 풀면서 느꼈던 점 및 유의사항은 아래와 같다...
1) 28번째 줄 int mid = s + (e - s) / 2;
를 int mid = (s + e) / 2;
로 써도 된다.
2) 정렬이 필요한 배열은 "매번" 복사해야 한다.
3) 48번째 줄 if(tmp[l] <= tmp[r])
☞ 등호 빠뜨리면 틀리더라...
4) 52-54번째 줄 : 순서를 조심해야 한다. A[idx++] = tmp[r++]
하고 cnt 업데이트 하면 틀린다.
순서가 반드시 1) 현재 idx와 r을 이용해 cnt 세기 → 2) 갯수 ++ 어야 한다.
5) 53번째 줄 : cnt += (m + 1 - l);
를 cnt += r - idx;
로 해도 된다. 원소가 앞으로 이동한 거리만큼 result에 더하는 것..
(참고)
✔ 병합 정렬 문제
[백준/JAVA] 24060번: 알고리즘 수업 - 병합 정렬 1
🔺 문제 24060번: 알고리즘 수업 - 병합 정렬 1 첫째 줄에 배열 A의 크기 N(5 ≤ N ≤ 500,000), 저장 횟수 K(1 ≤ K ≤ 108)가 주어진다. 다음 줄에 서로 다른 배열 A의 원소 A1, A2, ..., AN이 주어진다. (1 ≤ Ai
bono039.tistory.com
[백준/JAVA] 2751번: 수 정렬하기 2
🔺 문제 2751번: 수 정렬하기 2 첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지
bono039.tistory.com