intro : static 내부 class를 통해 문제를 풀어보자
문제
온라인 저지에 가입한 사람들의 나이와 이름이 가입한 순서대로 주어진다. 이때, 회원들을 나이가 증가하는 순으로, 나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬하는 프로그램을 작성하시오.
입력
첫째 줄에 온라인 저지 회원의 수 N이 주어진다. (1 ≤ N ≤ 100,000) 둘째 줄부터 N개의 줄에는 각 회원의 나이와 이름이 공백으로 구분되어 주어진다. 나이는 1보다 크거나 같으며, 200보다 작거나 같은 정수이고, 이름은 알파벳 대소문자로 이루어져 있고, 길이가 100보다 작거나 같은 문자열이다. 입력은 가입한 순서로 주어진다.
출력
첫째 줄부터 총 N개의 줄에 걸쳐 온라인 저지 회원을 나이 순, 나이가 같으면 가입한 순으로 한 줄에 한 명씩 나이와 이름을 공백으로 구분해 출력한다.
문제 풀이 (548ms)
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
// 입출력을 위한 BufferedReader, BufferedWriter, StringBuilder 객체 생성
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
// 입력값의 개수
int forCount = Integer.parseInt(br.readLine());
// Member 배열 선언
Member[] members = new Member[forCount];
// 반복문을 통해 Member 객체를 배열로 저장
for (int i = 0; i < forCount; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
// 이때 가입한 순서를 i로 Member 클래스의 index 값을 저장
members[i] = new Member(Integer.parseInt(st.nextToken()), st.nextToken(), i);
}
// 배열 정렬
Arrays.sort(members, (o1, o2) -> {
// 나이값을 기준으로 오름차순 정렬
if (o1.age != o2.age) {
return o1.age - o2.age;
} else {
// 나이값이 같다면 가입한 순서로 오름차순 정렬
return o1.index - o2.index;
}
});
// 정렬된 members 데이터 sb.append() 메서드를 통해 저장
for (Member member : members) {
sb.append(member.age).append(" ").append(member.name).append("\n");
}
// bw로 출력하기 위해 문자열로 변환 후 write
bw.write(sb.toString());
bw.flush();
// 자원 반납
bw.close();
br.close();
}
// Member 클래스 생성
// static 으로 생성하는 이유는 내부 클래스는 static 으로 생성해야
// 메모리 관점에서 효율적으로 관리할 수 있고, 누수를 막을 수 있다.
static class Member {
int age; // 나이
String name; // 이름
int index; // 가입 순서
// 생성자를 통한 객체 생성
public Member(int age, String name, int index) {
this.age = age;
this.name = name;
this.index = index;
}
}
}
문제 해석
이 문제는 기존에 풀던 정렬문제랑 크게 차이가 없었는데 관리해야하는 값의 개수가 2개에서 3개로 늘어남에 따라 어떻게 처리하는게 좋을지 생각하다가 배열을 통해 관리를 하는게 어떨지 생각하고 다음과 같이 문제를 풀어보았었다.
856ms 소요
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
// 입출력을 위한 BufferedReader, BufferedWriter, StringBuilder 객체 생성
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
// 입력값의 개수
int forCount = Integer.parseInt(br.readLine());
// 나이, 이름, 가입순서를 저장할 배열 선언
String[][] array = new String[forCount][3];
// 반복문을 통해 array 데이터 저장
for (int i = 0; i < forCount; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
array[i][0] = st.nextToken();
array[i][1] = st.nextToken();
array[i][2] = Integer.toString(i);
}
// 배열 정렬
Arrays.sort(array, (o1, o2) -> {
// 나이값을 기준으로 오름차순 정렬
if (!o1[0].equals(o2[0])) {
return Integer.parseInt(o1[0]) - Integer.parseInt(o2[0]);
} else {
// 나이값이 같다면 가입한 순서로 오름차순 정렬
return Integer.parseInt(o1[2]) - Integer.parseInt(o2[2]);
}
});
// 정렬된 array 데이터 sb.append() 메서드를 통해 저장
for (String[] arr : array) {
sb.append(arr[0]).append(" ").append(arr[1]).append("\n");
}
// bw로 출력하기 위해 문자열로 변환 후 write
bw.write(sb.toString());
bw.flush();
// 자원 반납
bw.close();
br.close();
}
}
static class를 사용하게된 이유
근데 위와같이 풀고나니까, 정렬하는 부분에서 각 값을 자꾸 형변환을 해줘야하는게 너무 신경이 쓰였다. 뭐 이대로 풀어도 정답처리되는 코드이지만 뭔가 석연치않는 부분이 남는거 같다는 생각이 들었다. 아무래도 정수형 데이터와 문자열 데이터를 같이 관리해야하다보니, 다른 자료구조를 사용하는게 좋을거 같다는 생각이 들었는데, 객체를 통해 자료구조를 만들어 보는게 어떨까? 라는 생각이 들었다.
static class를 사용하면서 얻게 되는 이점
가장 큰 이점은 형변환을 하지 않아도 되는점이다. 아무래도 정렬 로직에서 각 값을 계속해서 Integer.parseInt
를 하는게 시간복잡도 관점에서 크게 영향을 미치기도하고, 배열을 통해 3개의 데이터를 0,1,2 번 인덱스에 값을(나이,이름,가입순서) 할당하는게 누군가 보았을때 유지보수 관점에서도 크게 좋지 않는데 내부 클래스를 이용해서 객체로 관리하니 유연성 및 확장성 에서도 이점을 가져올수 있고 가독성 부분에서도 굉장히 쉽게 읽히는 부분이 생긴다.
마무리
처음으로 알고리즘 문제에서 객체를 활용해 문제를 풀어봤는데, 다음에도 혹시 관리포인트가 늘어나는 자료구조가 필요하다면 기존에 자바에서 제공해주는 자료구조 및 객체도 고민거리에 포함해서 생각해 보아야 겠다고 생각이 들었다.