코딩테스트/Programmers
[Programmers] 입문) 특이한 정렬
HONGGG
2023. 7. 20. 07:24
특이한 정렬
문제 설명
정수 n을 기준으로 n과 가까운 수부터 정렬하려고 합니다. 이때 n으로부터의 거리가 같다면 더 큰 수를 앞에 오도록 배치합니다. 정수가 담긴 배열 numlist와 정수 n이 주어질 때 numlist의 원소를 n으로부터 가까운 순서대로 정렬한 배열을 return하도록 solution 함수를 완성해주세요.
제한사항
- 1 ≤ n ≤ 10,000
- 1 ≤ numlist의 원소 ≤ 10,000
- 1 ≤ numlist의 길이 ≤ 100
- numlist는 중복된 원소를 갖지 않습니다.
입출력 예
numlist | n | result |
[1, 2, 3, 4, 5, 6] | 4 | [4, 5, 3, 6, 2, 1] |
[10000, 20, 36, 47, 40, 6, 10, 7000] | 30 | [36, 40, 20, 47, 10, 6, 7000, 10000] |
[0, 0, 0, 0] | 0 | [0, 0, 0, 0] |
[6, 10, 2] | 6 | [6, 10, 2] |
[3, 30, 34, 5, 9] | 9 | [9, 5, 3, 30, 34] |
[1, 2, 3, 4, 5] | 1 | [1, 2, 3, 4, 5] |
[3, 30, 34, 5, 9] | 99999 | [34, 30, 9, 5, 3] |
입출력 예 설명
입출력 예 #1
4에서 가까운 순으로 [4, 5, 3, 6, 2, 1]을 return합니다.
3과 5는 거리가 같으므로 더 큰 5가 앞에 와야 합니다.
2와 6은 거리가 같으므로 더 큰 6이 앞에 와야 합니다.
입출력 예 #2
30에서 가까운 순으로 [36, 40, 20, 47, 10, 6, 7000, 10000]을 return합니다.
20과 40은 거리가 같으므로 더 큰 40이 앞에 와야 합니다.
이번 문제는 그냥 생각나는데로 작성해보았다.
- 배열을 오름차순으로 나열한다.
- 주어진 n이 들어가는 위치를 판단한다
- 확인한 위치를 기준으로 좌우로 이동하며 차이가 더 작은 것을 순서대로 넣는다.
이때 실패하는 테스트 케이스 3이 있었다.
이에 대해 질문하기를 탐색해본 결과 n이 터무니 없이 큰 수인 경우 탐색 범위를 넘겨버리는 어이없는 실수를 하게 되었다.
이에 최종 수정한 코드는 다음과 같다.
using System;
public class Solution {
public int[] solution(int[] numlist, int n) {
int[] answer = new int[numlist.Length];
Array.Sort(numlist);
int position = 0;
for (int distance = 999999; position < numlist.Length; position++) {
int gap = Math.Abs(numlist[position] - n);
if (gap == 0 || distance == gap) {
answer[0] = numlist[position];
break;
}
if (distance < gap) {
answer[0] = numlist[--position];
break;
}
if (distance > gap)
distance = gap;
}
// 만약 n이 너무 큰 경우
if (position == numlist.Length) {
answer[0] = numlist[numlist.Length - 1];
position--;
}
// 선택된 위치부터 좌우 탐색
for (int k = 1, goRight = 1, goLeft = 1; k < numlist.Length; k++) {
int rightPosition = position + goRight;
int leftPosition = position - goLeft;
// 오른쪽으로 갈수 없는 경우 왼쪽 원소만 넣기
if (rightPosition > numlist.Length - 1) {
answer[k] = numlist[leftPosition];
goLeft++;
continue;
}
// 왼쪽으로 갈수 없는 경우 오른쪽 원소만 넣기
if (leftPosition < 0) {
answer[k] = numlist[rightPosition];
goRight++;
continue;
}
int leftGap = n - numlist[leftPosition];
int rightGap = numlist[rightPosition] - n;
// 오른쪽이 더 크면 왼쪽 원소를 넣기
if (rightGap > leftGap) {
answer[k] = numlist[leftPosition];
goLeft++;
}
// 왼쪽이 더 크면 오른쪽 원소를 넣기
if (leftGap > rightGap) {
answer[k] = numlist[rightPosition];
goRight++;
}
// 양쪽이 크기가 같으면 오른쪽, 왼쪽순으로 넣기
if (rightGap == leftGap) {
answer[k] = numlist[rightPosition];
k++;
answer[k] = numlist[leftPosition];
goRight++;
goLeft++;
}
}
return answer;
}
}
다른 분들의 풀이 중에는 크게 3가지 풀이가 있었다.
- OrderBy와 ThenByDescending를 활용한 풀이
- 배열 원소를 하나하나 순차적으로 다른 원소들과 비교하기
- Dictionary를 활용하여 key값을 거리로, value를 숫자로 사용하여 정렬하기
using System;
using System.Linq;
public class Solution
{
public int[] solution(int[] numlist, int n)
{
int[] answer = new int[numlist.Length];
answer = numlist.OrderBy(x => Math.Abs(n-x)).ThenByDescending(x=>x).ToArray();
return answer;
}
}
using System;
public class Solution {
public int[] solution(int[] numlist, int n) {
int[] answer = new int[] {};
for(int i = 1; i < numlist.Length; ++i) {
for(int j = 0; j < i + 1; ++j) {
int diff = Math.Abs(numlist[i] - n);
int diff2 = Math.Abs(numlist[j] - n);
if( diff < diff2 ) {
int temp = numlist[j];
numlist[j] = numlist[i];
numlist[i] = temp;
} else if( diff == diff2 ) {
if( numlist[i] > numlist[j] ) {
int temp = numlist[j];
numlist[j] = numlist[i];
numlist[i] = temp;
}
}
}
}
return numlist;
}
}
using System;
using System.Collections.Generic;
public class Solution {
public int[] solution(int[] numlist, int n)
{
List<(int, int)> list = new List<(int, int)>();
foreach (var it in numlist)
{
list.Add((it, Math.Abs(it - n)));
}
list.Sort((v1, v2) =>
{
if (v1.Item2 == v2.Item2)
{
return -v1.Item1.CompareTo(v2.Item1);
}
return v1.Item2.CompareTo(v2.Item2);
});
List<int> answer = new List<int>();
foreach (var it in list)
{
answer.Add(it.Item1);
}
return answer.ToArray();
}
}