Language/C#
[C#] 백준 24060번 알고리즘 수업 - 병합 정렬 1
석영
2024. 5. 8. 21:45
반응형
[ 문제 ]
오늘도 서준이는 병합 정렬 수업 조교를 하고 있다. 아빠가 수업한 내용을 학생들이 잘 이해했는지 문제를 통해서 확인해보자.
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++];
}
[ 코드 ]
1. 내 코드
using System;
using System.Collections.Generic;
class Program
{
static List<int> MergeSort(List<int> arr)
{
// 길이가 1 이하시 반환
if (arr.Count <= 1)
return arr;
// 반으로 나누기 위한 mid 계산
int mid = (arr.Count + 1) / 2;
// 리스트를 반으로 나눠 각각의 부분 리스트에 재귀적으로 합병 정렬 적용
List<int> lowArr = MergeSort(arr.GetRange(0, mid));
List<int> highArr = MergeSort(arr.GetRange(mid, arr.Count - mid));
// 정렬된 결과를 저장할 리스트
List<int> sortedArr = new List<int>();
// lowArr와 highArr를 비교하면서 합병
int l = 0, h = 0;
while (l < lowArr.Count && h < highArr.Count)
{
// lowArr과 highArr에서 작은 값을 선택하여 sortedArr에 추가
if (lowArr[l] <= highArr[h])
{
sortedArr.Add(lowArr[l]);
ans.Add(lowArr[l]); // 정렬된 값을 ans 리스트에 추가
l++;
}
else
{
sortedArr.Add(highArr[h]);
ans.Add(highArr[h]); // 정렬된 값을 ans 리스트에 추가
h++;
}
}
// 남은 요소들을 sortedArr에 추가
while (l < lowArr.Count)
{
sortedArr.Add(lowArr[l]);
ans.Add(lowArr[l]); // 정렬된 값을 ans 리스트에 추가
l++;
}
while (h < highArr.Count)
{
sortedArr.Add(highArr[h]);
ans.Add(highArr[h]); // 정렬된 값을 ans 리스트에 추가
h++;
}
// 정렬된 리스트 반환
return sortedArr;
}
// 결과 값 저장을 위한 정적 리스트
static List<int> ans = new List<int>();
static void Main(string[] args)
{
string[] inputs = Console.ReadLine().Split();
int N = int.Parse(inputs[0]);
int K = int.Parse(inputs[1]);
MergeSort(new List<int>(Array.ConvertAll(Console.ReadLine().Split(), int.Parse)));
Console.WriteLine((K <= ans.Count) ? ans[K - 1].ToString() : "-1");
}
}
2. 다른 사람 코드
using System.Text;
namespace ConsoleApp1
{
internal class Program
{
static int target;
static int[] a;
static StringBuilder sb = new StringBuilder();
public static void Main(string[] args)
{
StreamReader input = new StreamReader(
new BufferedStream(Console.OpenStandardInput()));
StreamWriter output = new StreamWriter(
new BufferedStream(Console.OpenStandardOutput()));
int[] arr = Array.ConvertAll(input.ReadLine().Split(' '), int.Parse);
int n = arr[0];
target = arr[1];
a = Array.ConvertAll(input.ReadLine().Split(' '), int.Parse);
// 이분 탐색 함수 호출
find(0, n - 1);
// 결과가 없을 경우 -1 출력
if (sb.Length == 0)
sb.Append("-1");
output.Write(sb);
input.Close();
output.Close();
}
// 이분 탐색 함수
static void find(int start, int end)
{
// 범위가 잘못되었거나 target이 0 이하일 경우 종료
if (start == end || target <= 0) return;
// 중간 값 계산
int mid = (start + end) / 2;
// 왼쪽과 오른쪽에 대해 재귀적으로 호출
find(start, mid);
find(mid + 1, end);
// target이 유효하고 범위 내에 있을 때
if (target > 0 && target <= end - start + 1)
{
// 배열의 일부를 정렬하고 결과에 추가
Array.Sort(a, start, end - start + 1);
sb.Append($"{a[start + target - 1]}");
}
// target 갱신
target -= end - start + 1;
}
}
}
나중에 봤을때 주석보고 이해 쉽게 하기위해서 주석을 달아놨다.......
이러면 별로 안좋으려나
[ 실행화면 ]
https://www.acmicpc.net/problem/24060
반응형