| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- todomate
- 알고리즘
- add
- 인프런
- 2869
- 우선순위
- 큐
- spring
- 클론코딩
- 데이터베이스
- 람다식
- github
- 정렬
- 11651
- Push
- 스프링
- gradle
- 백엔드
- Lock
- assertj
- 자바
- static
- Spring Security
- Java
- build
- 백준
- 투두메이트
- 11650
- 로그인
- 계수정렬
- Today
- Total
여러가지 이야기
[BOJ] 11650, 11651번: 좌표 정렬하기 (Java) 본문
🔗 https://www.acmicpc.net/problem/11650
🔗 https://www.acmicpc.net/problem/11651
좌표 정렬하기(11650번) 문제는 N개의 좌표를 x좌표가 증가하는 순으로 정렬, 만약 x좌표가 같으면 y좌표가 증가하는 순으로 정렬하는 문제이다.
'딱 처음 이 문제를 봤을 때는 merge sort와 같은 정렬 알고리즘을 사용하면 되는건가?'라고 생각해 시도 해봤는데, 한 좌표에는 x값, y값이 모두 있기에 정렬할 시에 코드가 복잡해질 수밖에 없었다. 그리고 에러가 발생하기도 함...

당연히 정렬 알고리즘을 쓰겠지라며 생각했던 나는 해답을 찾다 Arrays.sort와 Comparator, Comparable 개념을 접하게 되었다.
이 개념들을 활용하면 아주 간결하게 코드를 짤 수 있었다. 우선 이 낯선 이 개념들을 차근차근 정리해보자.
Arrays.sort
✔️ Arrays.sort 기본 정렬
Arrays.sort는 Arrays 클래스의 sort 메소드로, 자바에서 배열을 정렬할 때 사용하는 메소드이다. 배열의 요소를 오름차순으로 정렬한다.
int []arr = {5,4,3,2,1};
Arrays.sort(arr);
for (i=0; i<arr.length; i++) {
System.out.print(arr[i] + " ");
}
위와 같은 코드의 출력 결과는 1 2 3 4 5 일 것이다.
✔️ Comparator를 사용한 Arrays.sort 정렬
또한 sort 메소드를, 다음과 같이 파라미터에 Comparator를 넣어 사용할 수도 있다.

💡 Compartor와 Comparable
: 객체끼리 비교하는 데 유용한 인터페이스
Comparator
- compare(T o1, T o2) 메소드 구현 해야 함
- 두 매개변수 객체(o1, o2) 비교
class Product implements Comparator<Product> {
int count; // 수량
int price; // 가격
Product(int count, int price) {
this.count = count;
this.price = price;
}
@Override
public int compare(Product o1, Product o2) {
// o1의 가격이 o2의 가격보다 크다면 양수
if(o1.price > o2.price) {
return 1;
}
// o1의 가격이 o2의 가격과 같다면 0
else if(o1.price == o2.price) {
return 0;
}
// o1의 가격이 o2의 가격보다 작다면 음수
else {
return -1;
}
// 혹은 이렇게
// return o1.price-o2.price;
}
}
Comparable
- compareTo(T o) 메소드 구현 해야 함
- 자기 자신과 매개변수 객체 비교 → 정수를 반환함
- 자기 자신 기준으로 상대방과의 차이 값을 비교해 반환.
class Product implements Comparable<Product> {
int count; // 수량
int price; // 가격
Product(int count, int price) {
this.count = count;
this.price = price;
}
@Override
public int compareTo(Product o) {
// 자기 자신의 count가 o의 count보다 크다면 양수
if(this.count > o.count) {
return 1;
}
// 자기 자신의 count와 o의 count가 같다면 0
else if(this.count == o.count) {
return 0;
}
// 자기 자신의 count가 o의 count보다 작다면 음수
else {
return -1;
}
// 혹은 이렇게
// return this.count-o.count;
}
}
=> 정확히는 단지 양수(1), 0, 음수(-1)를 반환하는 게 아니라 대소관계를 나타내는 것
그럼 좌표를 어떻게 비교할까?
우선 2차원 배열은 1차원 배열들의 set라고 보면 된다.
예를 들어 int[3][2] = {1,2,3,4,5,6}이 있다고 가정하자. 이걸 {(1,2), (3,4), (5,6)}으로 나타낼 수 있으며, 이것은 1차원 배열 3개를 합친 set이라고 볼 수 있겠다. 이 각 1차원 배열을 e1, e2, e3라고 해보자({e1, e2, e3}).
int []e1 = {1,2}이고, e1[0] 즉, 이 배열의 첫 번째 요소(x좌표)는 1이 될 것이다.
우리는 e1과 e2의 각 x좌표를 우선 비교하고 싶다. 이걸 두 객체를 비교하는 Comparator 인터페이스의 compare(o1,o2) 메소드로 구현하면
@Override
public int compare(int []e1, int []e2){
return e1[0] - e2[0];
}
이런 식으로 표현할 수 있다.
문제 조건은 x좌표를 기준으로 점을 오름차순 정렬하고, 만약 x좌표가 같으면 y좌표를 오름차순으로 정렬하라 했기에 if-else문으로 이 조건을 나눠주자.
@Override
public int compare(int []e1, int []e2) {
if(e1[0] == e2[0])
return e1[1] - e[1]; // y 좌표 비교
else
return e1[0] - e2[0]; // x 좌표 그냥 비교
}
다시 Arrays.sort()로 돌아가, 위 comparator를 파라미터로 하여 배열을 정렬해보자.
만약 int[5][2]짜리 배열이 있다면,
int [][]arr = new int[5][2];
Arrays.sort(arr, new Comparator<int[]>() {
@Override
public int compare(int []e1, int []e2){
if (e1[0] == e2[0])
return e1[1] - e2[1];
else
return e1[0] - e2[0];
}
});
여기서 new Comparator<>(){} 부분은 익명 클래스로 쓰였다. (익명 클래스는 클래스의 이름이 없고, 단 하나의 객체만 생성 가능한 클래스라는 특징이 있다.)
💭 내가 착각했던 부분
int [][]arr = new int[5][2];
Arrays.sort(arr, new Comparator<int [][]>() {
@Override
public compare(int [][]e1, int [][]e2) {
return e1.[0][0] - e2.[1][0];
.
.
.
}
});
배열 요소를 비교해야하니까 대충 '이런 식으로 코드를 짜면 되지 않을까?'라며 생각했다.
하지만 이것은 틀렸다! 왜냐하면 Arrays.sort는 1차원 배열을 정렬할 때 사용하는 것이지 2차원 배열 자체를 직접 비교하는 것이 아니기 때문이다.
💡 람다식
위 식을 람다식으로 더 간결하게 정리할 수 있다.
함수 이름을 지정하지 않고 함수를 가독성 좋게, 짧게 만들 수 있는 문법이다. 즉, 함수 이름을 지정하지 않는다는 점에서 익명 클래스로도 변환할 수 있는 것이다. 위 익명 클래스를 람다식으로 짧게 나타내보자.
Arrays.sort(arr, (e1, e2) -> {
if (e1[0] == e2[0])
return e1[1] - e2[1];
else
return e1[0] - e2[0];
});
람다식의 특징
예시
// 메소드
int min(int x, int y) {
return x < y ? x : y;
}
// 람다 표현식
(x, y) -> x < y ? x : y;
- 매개변수(파라미터) 타입을 생략할 수 있다.
- 매개변수가 하나면 괄호도 생략 가능하다.
- 함수 몸체가 명령문 하나로만 이뤄져있다면 중괄호{}도 예시처럼 생략이 가능하다.
결국은 다음과 같은 코드로 정리할 수 있었다.
11650
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class BOJ_11650_2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int[][] arr = new int[N][2];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
arr[i][0] = Integer.parseInt(st.nextToken());
arr[i][1] = Integer.parseInt(st.nextToken());
}
// for (int i = 0; i < N; i++) {
// for (int j = 0; j < 2; j++) {
// arr[i][j] = Integer.parseInt(br.readLine());
// }
// }
// Arrays.sort(arr, new Comparator<int[]>() {
// public int compare(int[] e1, int[] e2) {
// if (e1[0] == e2[0])
// return e1[1] - e2[1];
// else return e1[0] - e2[0];
// }
// });
Arrays.sort(arr, (e1, e2) -> {
if(e1[0] == e2[0])
return e1[1] - e2[1];
else return e1[0] - e2[0];
});
for (int i = 0; i < N; i++) {
System.out.println(arr[i][0]+" "+arr[i][1]);
}
}
}
11651번은 11650번과 같은 유형이지만, y좌표로 점을 비교하여 오름차순 정렬하며 만약 두 점의 y좌표가 같다면 x좌표를 기준으로 오름차순 정렬한다는 차이가 있다. 그 점만 유의해서 조건문을 살짝 변형해주면 된다.
11651
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class BOJ_11651 {
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int [][]arr = new int[N][2];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
arr[i][0] = Integer.parseInt(st.nextToken());
arr[i][1] = Integer.parseInt(st.nextToken());
}
// Arrays.sort(arr, new Comparator<int[]>() {
// @Override
// public int compare(int[] o1, int[] o2) {
// if(o1[1] == o2[1])
// return o1[0] - o2[0];
// else return o1[1] - o2[1];
// }
// });
Arrays.sort(arr, (e1, e2) -> {
if(e1[1] == e2[1])
return e1[0] - e2[0];
else return e1[1] - e2[1];
});
for (int i = 0; i < N; i++) {
System.out.println(arr[i][0]+" "+arr[i][1]);
}
}
}
람다식, Comparator, Comparable 모두 나에게 생소한 개념이어서 문제를 쉽게 풀기 어려웠다. 또한, 알고 있다고 생각했던 Arrays.sort는 사실 파라미터로 Comparator를 넣는 형태도 있는 등, 더 다양하다는 점을 발견할 수 있었다.
자바 개념을 더 확실히 꼼꼼히 공부해야함을 뼈저리게 느낄 수 있었다. 파이팅!

'study > BOJ' 카테고리의 다른 글
| [BOJ] 11866번: 요세푸스 문제 (0) | 2025.01.10 |
|---|---|
| [BOJ] 1920번: 수 찾기 (0) | 2024.11.04 |
| [BOJ] 10989번: 수 정렬하기 3 (3) | 2024.11.01 |
| [BOJ] 2231번: 분해합 (Java) (0) | 2024.07.13 |
| [BOJ] 2896번: 달팽이는 올라가고 싶다 (Java) (1) | 2024.04.01 |