문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/42748
배열 array의 i번째 숫자부터 j번째 숫자까지 자르고 정렬했을 때, k번째에 있는 수를 구한다. commands의 각 원소는 [i, j, k]이고, 이 연산을 모든 command에 대해 적용한 결과를 배열로 반환해야 한다.
import java.lang.StringBuilder;
import java.util.Arrays;
class Solution {
public int[] solution(int[] array, int[][] commands) {
int[] answer = new int[commands.length];
int start = 0;
int end = 0;
int target = 0;
int answerCnt = 0;
for (int i = 0; i < commands.length; i++) {
start = commands[i][0] - 1;
end = commands[i][1] - 1;
target = commands[i][2] - 1;
int cnt = 0;
int[] tempArr = new int[(end - start + 1)];
System.out.println(tempArr.length);
for (int j = start; j <= end; j++) {
tempArr[cnt] = array[j];
cnt++;
}
Arrays.sort(tempArr);
for (int k = 0; k < tempArr.length; k++) {
if (k == target) {
answer[answerCnt] = tempArr[k];
answerCnt++;
}
}
}
return answer;
}
}
tempArr[cnt] = array[j]).k == target을 비교하는 방식으로 짰다. 정렬된 배열은 인덱스로 바로 접근 가능한데 이 사실을 활용하지 못했다.answerCnt라는 변수를 따로 만들어서 관리했는데, 사실 바깥쪽 반복문의 i와 같은 값이라 불필요한 변수였다.System.out.println을 정리하지 않고 그대로 뒀다.import java.util.Arrays;
class Solution {
public int[] solution(int[] array, int[][] commands) {
int[] answer = new int[commands.length];
for (int i = 0; i < commands.length; i++) {
int start = commands[i][0] - 1;
int end = commands[i][1];
int target = commands[i][2] - 1;
int[] temp = Arrays.copyOfRange(array, start, end);
Arrays.sort(temp);
answer[i] = temp[target];
}
return answer;
}
}
Arrays.copyOfRange(array, start, end)로 대체했다.temp[target]으로 바로 접근하면 된다.answerCnt 대신 바깥 반복문의 i를 그대로 사용해서 변수를 줄였다.copyOfRange의 from/to 규칙Arrays.copyOfRange(array, from, to)는 from은 포함, to는 포함하지 않는(half-open interval) 규칙을 따른다. String.substring(from, to), List.subList(from, to)도 동일한 규칙이다.
이렇게 만든 이유:
to - from이 곧 잘라낸 배열의 길이가 된다. 예를 들어 인덱스 1~4 (4개 원소)를 뽑고 싶으면 copyOfRange(array, 1, 5)처럼 써야 하고, 5 - 1 = 4로 개수가 딱 맞아떨어진다.to도 포함이었다면 길이를 구할 때마다 to - from + 1을 계산해야 해서 off-by-one 실수가 나기 쉽다.[0,3)과 [3,6)처럼 겹치거나 빠지는 부분 없이 자연스럽게 연결된다.그래서 문제의 j번째(1-indexed, inclusive)까지 자르려면 배열 인덱스로는 j-1까지 필요한데, copyOfRange의 to는 exclusive이므로 j-1+1 = j, 즉 commands[i][1]을 그대로 넣으면 된다.
풀이를 정리하다가 Arrays.sort(temp, (o1, o2) -> o1 - o2)처럼 Comparator를 써서 정렬하면 어떻게 되는지 궁금해서 짚어봤다.
compare(o1, o2)가 음수를 반환하면 o1이 o2보다 앞에 온다. o1 - o2는 o1 < o2일 때 음수이므로, 이 Comparator는 오름차순 정렬이 된다.Arrays.sort(배열, Comparator) 형태는 int[] 같은 primitive 타입 배열에는 쓸 수 없다. Comparator는 인터페이스이고 인터페이스는 객체(Object)에만 적용되는데, int는 객체가 아니기 때문이다.temp가 int[]라면 커스텀 Comparator 없이 그냥 Arrays.sort(temp)만 써도 충분하다 (기본 동작이 오름차순). 굳이 Comparator로 커스텀 정렬을 하고 싶다면 Integer[]로 박싱해서 선언해야 한다.Arrays.copyOfRange + Arrays.sort + 인덱스 직접 접근으로 충분히 간결하게 풀린다.copyOfRange, substring, subList 등 Java의 범위 관련 API는 "from 포함, to 미포함" 규칙을 공통으로 따른다는 걸 기억해두면 좋다.Integer[])으로 바꿔야 한다.