코딩테스트/Programmers

[프로그래머스] 특이한 정렬

grove1212 2025. 1. 30. 19:23

생각해볼 점

1. 정석대로 커스텀 정렬을 이용해 풀기

2. if문으로 분기조건 설정해서 풀기

1번으로 풀면 예외가 존재할 수가 없다. 그러나 나는 사파인 2번으로 문제풀이를 전개했기 때문에, 예외사항을 잘 처리했는지가 문제를 풀 때 생각했던 포인트였다. 이 문제를 통해 좋은 테스트케이스를 어떻게 작성해야하는지에 대해 인사이트가 조금은 생긴 것 같다.

테스트 케이스는 엣지 케이스여야 한다.

이 문제에서 생각해볼 법한 테스트케이스는 다음과 같다.

  1. n이 list의 원소인가
  2. n이 list의 원소들은 아니지만, 정렬했을 때 가장 큰 값과 가장 작은값의 범위 사이에 존재하는가
  3. n이 list의 원소중 최솟값보다 작은가
  4. n이 list의 원소중 최솟값과 같은가
  5. n이 list의 원소중 최댓값보다 큰가
  6. n이 list의 원소중 최댓값인가

다음을 모두 만족했을 때 웬만한 모든 테스트 케이스를 통과할 수 있고, 나는 해당 테스트케이스를 만족하도록 코드를 짜서 통과할 수 있었다. 그래서 내 코드는 다음과 같다.

1. 본인 코드

import java.util.*;
import java.util.stream.*;

class Solution {
    public int[] solution(int[] numlist, int n) {
        int[] answer = {};
        List<Integer> list = new LinkedList<>();
        Arrays.sort(numlist);
        int minIdx = -1;
        int plusIdx = numlist.length;
        for(int i = 0; i < numlist.length; i++){
            if(numlist[i] == n){
                list.add(numlist[i]);
                minIdx = i-1;
                plusIdx = i+1;
                break;
            } else if(i+1 != numlist.length && numlist[i] < n && numlist[i+1] > n){
                minIdx = i;
                plusIdx = i+1;
                break;
            } else if(numlist[0] > n){
                plusIdx = 0;
                break;
            } else if(numlist[numlist.length - 1] < n){
                minIdx = numlist.length -1;
                break;
            }
        }

        while(minIdx != -1 || plusIdx != numlist.length){
            if(minIdx != -1 && plusIdx != numlist.length){
                int mindist = n - numlist[minIdx];
                int maxdist = numlist[plusIdx] - n;
                if(maxdist < mindist){
                    list.add(numlist[plusIdx++]);
                } else if(maxdist > mindist) {
                    list.add(numlist[minIdx--]);
                } else{
                    if(numlist[minIdx] > numlist[plusIdx]){
                        list.add(numlist[minIdx--]);
                    } else {
                        list.add(numlist[plusIdx++]);
                    }
                }
            } else if(minIdx == -1){
                list.add(numlist[plusIdx++]);
            } else if(plusIdx == numlist.length){
                list.add(numlist[minIdx--]);
            }
        }


        return list.stream().mapToInt(i -> i).toArray();
    }
}

더 쉽게 작성한 분이 있는지 궁금해서 다른 분들의 풀이를 구경한 결과 배울만한 코드는 다음과 같았다.

일단 다른 분들은 comparator을 이용한 분들이 많았다. 이름부터가 정렬이다 보니 다른 분들은 정렬로 푸신 것을 볼 수 있는데 사실 아래 코드가 좀 더 정석인 것 같다. 보면서 정렬에 더 익숙해질 수 있었다.

다른 분 풀이 1

import java.util.Arrays;

class Solution {
    public int[] solution(int[] numList, int n) {
        return Arrays.stream(numList)
                .boxed()
                .sorted((a, b) -> Math.abs(a - n) == Math.abs(b - n) ? b.compareTo(a) : Integer.compare(Math.abs(a - n), Math.abs(b - n)))
                .mapToInt(Integer::intValue)
                .toArray();
    }
}

풀이 분석

1. boxed

int를 Integer로 감싸줄 때 사용한다. sorted와 같은 함수를 사용하기 위해 쓴 것 같다.

2. Integer::intValue

mapToInt함수의 인자로 주어진 Integer::intValue는 Integer 클래스의 intValue 함수를 값으로 넘겨줘서 사용한 것이다. 이에 관련해서는 추가 공부 후 링크 청부하겠다.

3. sorted 부분

  1. 조건1 : 거리가 같다면, 더 큰 값을 먼저 내보낸다(내림차순)
    • compareTo 함수의 구현은 다음과 같이 되어있다.
      //compareTo 함수 구현부 
      public int compareTo(Integer anotherInteger) { 
      	return compare(this.value, anotherInteger.value);
      } 
      
      //compare 함수 구현부 
      public static int compare(int x, int y) { 
      	return (x < y) ? -1 : ((x == y) ? 0 : 1); 
      }


    • ` b.compareTo(a) `
      • 정렬의 로직은 음수, 0, 양수 순으로 정렬된다.
      • 함수의 결과가 음수일 때, b가 앞에 온다.
      • 함수의 결과가 양수일 때, a가 앞에 온다.
    • compare(x, y) 함수는 앞에 있는 게 작을 때 음수, 클 때 양수이다. (기본적으로 오름차순)
    • 근데, 현재 compare의 인수가 거꾸로 주어져있다. 그러므로 내림차순 정렬이 적용되는 것이다.
  2. 거리가 다르다면, 더 가까운 거리 순으로 Integer의 내장함수 compare 함수를 사용한다.다른 분 풀이 2

 

import java.util.PriorityQueue;

class Solution {
    public int[] solution(int[] numlist, int n) {

        PriorityQueue<Integer> que = new PriorityQueue<>(
                (a, b) -> Math.abs(a - n) == Math.abs(b - n) ? b - a : Math.abs(a - n) - Math.abs(b - n));

        for (int num : numlist)
            que.add(num);

        int idx = 0;

        while (!que.isEmpty())
            numlist[idx++] = que.poll();

        return numlist;
    }
}