24060번: 알고리즘 수업 - 병합 정렬 1
문제 )
오늘도 서준이는 병합 정렬 수업 조교를 하고 있다. 아빠가 수업한 내용을 학생들이 잘 이해했는지 문제를 통해서 확인해보자.
N개의 서로 다른 양의 정수가 저장된 배열 A가 있다. 병합 정렬로 배열 A를 오름차순 정렬할 경우 배열 A에 K 번째 저장되는 수를 구해서 우리 서준이를 도와주자.
크기가 N인 배열에 대한 병합 정렬 의사 코드는 다음과 같다.
merge_sort(A[p..r]) { # A[p..r]을 오름차순 정렬한다.
if (p < r) then {
q <- ⌊(p + r) / 2⌋; # q는 p, r의 중간 지점
merge_sort(A, p, q); # 전반부 정렬
merge_sort(A, q + 1, r); # 후반부 정렬
merge(A, p, q, r); # 병합
}
}
# A[p..q]와 A[q+1..r]을 병합하여 A[p..r]을 오름차순 정렬된 상태로 만든다.
# A[p..q]와 A[q+1..r]은 이미 오름차순으로 정렬되어 있다.
merge(A[], p, q, r) {
i <- p; j <- q + 1; t <- 1;
while (i ≤ q and j ≤ r) {
if (A[i] ≤ A[j])
then tmp[t++] <- A[i++]; # tmp[t] <- A[i]; t++; i++;
else tmp[t++] <- A[j++]; # tmp[t] <- A[j]; t++; j++;
}
while (i ≤ q) # 왼쪽 배열 부분이 남은 경우
tmp[t++] <- A[i++];
while (j ≤ r) # 오른쪽 배열 부분이 남은 경우
tmp[t++] <- A[j++];
i <- p; t <- 1;
while (i ≤ r) # 결과를 A[p..r]에 저장
A[i++] <- tmp[t++];
}
입력 :
첫째 줄에 배열 A의 크기 N(5 ≤ N ≤ 500,000), 저장 횟수 K(1 ≤ K ≤ 10^8)가 주어진다.
다음 줄에 서로 다른 배열 A의 원소 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 10^9)
출력 :
배열 A에 K 번째 저장 되는 수를 출력한다. 저장 횟수가 K 보다 작으면 -1을 출력한다.
풀이)
병합 정렬을 배우고, 병합 정렬에 익숙해지고자 만만하게 덤빈 문제,
분명 정렬을 제대로 짠 것 같은데 이상하게 답이 틀려서 한참을 해멨다.
답이 틀린 이유는 이거였다.
예제 1번을 예시로 설명해보면
처음에 내가 짠 코드는 4 5 // 1 3 2 의 방식으로 나누어 병합 정렬을 진행했지만,
문제에서는 4 5 1 // 3 2 와 같이 나누어 병합 정렬을 진행했기 때문에 답이 다르게 나온 것이었다.
이를 해결하기 위해 math 라이브러리를 불러 2로 나누었을 때 반올림을 해 해결하였다.
1. deque를 이용한 병합 정렬
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
|
from collections import deque
import math
# 하나씩 정렬 할때마다 카운트를 올려준다.
def check():
global cnt , ans, a
cnt += 1
# 카운트가 k에 도달하였을 때 정답을 갱신해준다.
if cnt == k:
ans = a
def merge(left, right):
global cnt, a
# 정렬하여 넣어 줄 결과 리스트
result = deque()
# left와 right가 모두 빌때까지 반복한다.
while len(left) or len(right):
# 크기를 비교하여 result에 넣어주는 과정.
# 수를 넣어줄 때마다 check를 해준다.
if len(left) and len(right):
if left[0] <= right[0]:
a = left[0]
check()
result.append(left.popleft())
else:
a = right[0]
check()
result.append(right.popleft())
elif len(left) and not len(right):
a = left[0]
check()
result.append(left.popleft())
elif len(right) and not len(left):
a = right[0]
check()
result.append(right.popleft())
return result
# 병합 정렬을 위해 반으로 나누고, 이후 병합을 해준다.
def merge_sort(li):
if len(li) == 1:
return li
mid = math.ceil(len(li)/2)
left = deque()
right = deque()
for i in range(mid):
left.append(li[i])
for i in range(mid, len(li)):
right.append(li[i])
left = merge_sort(left)
right = merge_sort(right)
return merge(left, right)
n, k = map(int, input().split())
li = list(map(int, input().split()))
cnt = 0
ans = -1
merge_sort(li)
print(ans)
|
cs |
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
|
import math
def check():
global cnt, ans
cnt += 1
if cnt == k:
ans = a
def merge_sort(li):
if len(li) == 1:
return li
mid = math.ceil(len(li)/2)
left = merge_sort(li[:mid])
right = merge_sort(li[mid:])
return merge(left, right)
def merge(left, right):
global a
result = []
left_idx = 0
right_idx = 0
while left_idx < len(left) and right_idx < len(right):
if left[left_idx] < right[right_idx]:
a = left[left_idx]
check()
result.append(left[left_idx])
left_idx += 1
else:
a = right[right_idx]
check()
result.append(right[right_idx])
right_idx += 1
if left_idx == len(left):
while right_idx < len(right):
a = right[right_idx]
check()
result.append(right[right_idx])
right_idx += 1
if right_idx == len(right):
while left_idx < len(left):
a = left[left_idx]
check()
result.append(left[left_idx])
left_idx += 1
return result
n, k = map(int, input().split())
li = list(map(int, input().split()))
ans = -1
cnt = 0
merge_sort(li)
print(ans)
|
cs |
출처 : https://www.acmicpc.net/problem/24060
24060번: 알고리즘 수업 - 병합 정렬 1
첫째 줄에 배열 A의 크기 N(5 ≤ N ≤ 500,000), 저장 횟수 K(1 ≤ K ≤ 108)가 주어진다. 다음 줄에 서로 다른 배열 A의 원소 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 109)
www.acmicpc.net
'Develop > 백준 (python)' 카테고리의 다른 글
[백준] 1389번: 케빈 베이컨의 6단계 법칙 (python) (0) | 2022.04.01 |
---|---|
[백준] 14726번: 현수막 (python) (0) | 2022.03.31 |
[백준] 11052번: 카드 구매하기 (python) (0) | 2022.03.30 |
[백준] 2668번: 숫자고르기 (python) (0) | 2022.03.30 |
[백준] 1520번: 내리막 길 (python) (0) | 2022.03.28 |