https://school.programmers.co.kr/learn/courses/30/lessons/155651
내 코드
import java.util.*;
class Solution {
private int answer = 1;
public int solution(String[][] book_time) {
//0
int[][] int_book_time = convertStringArrToIntArr(book_time);
//1
sortByCheckout(int_book_time);
//2. 현재 사용중인 방 배열 추가해서 초기값으로 첫번째 요소 삽입 & answer++;
List<Integer> occupied = new ArrayList<>();
occupied.add(int_book_time[0][1]);
//3
calc(int_book_time, occupied);
//4. return answer
return answer;
}
//0. String[][] -> int[][]
private int[][] convertStringArrToIntArr(String[][] book_time){
int size = book_time.length;
int[][] int_book_time = new int[size][2];
for(int i=0; i<size; i++){
String[] checkinSplited = splitTime(book_time[i][0]);
String[] checkoutSplited = splitTime(book_time[i][1]);
int_book_time[i][0] = makeIntTime(checkinSplited);
int_book_time[i][1] = makeIntTime(checkoutSplited);
}
return int_book_time;
}
private String[] splitTime(String str){
String[] arr = str.split(":");
return arr;
}
private int makeIntTime(String[] splited){
StringBuilder sb = new StringBuilder();
sb.append(splited[0]);
sb.append(splited[1]);
return Integer.parseInt(sb.toString());
}
//1. 퇴실 시간을 기준으로 정렬
private void sortByCheckout(int[][] book_time){
Arrays.sort(book_time, Comparator.comparingInt((int[] o) -> o[1]));
}
//3. 반복문 돌며 사용중인 방 배열 내 요소들의 퇴실시간+10 이 현재 요소의 입실 시간보다 이르거나 같을 경우 해당 요소들 삭제,
// 현재 요소 append / 없을 경우 append후 answer++
//아니면 현재answer보다 occupied의 size가 작을 때, list에 삽입하고 answer은 카운트 x. 그러나, 이상일 때, 현재 타임과 요소+10들을 비교, 뺄게 잇으면 삭제, 삭제 이후도 answer보다 크면 현재 타임 삽입 및 answer++
private void calc(int[][] book_time, List<Integer> occupied){
for(int i=1; i<book_time.length; i++){
// System.out.println("occupied: "+occupied);
if(occupied.isEmpty()){
occupied.add(book_time[i][1]);
continue;
}
boolean flag=false;
for(int j=0; j<occupied.size(); j++){
if(occupied.get(j) + 10 <= book_time[i][0]){
occupied.remove(j);
flag=true;
}
}
if(!flag){
answer++;
}
occupied.add(book_time[i][1]);
}
// System.out.println("final occupied: "+occupied);
}
}
//퇴실 후 10분까지 같은 방 사용 불가
정답 코드1
import java.util.*;
class Solution {
public int solution(String[][] book_time) {
int answer = 0;
//1.
int[][] book_time_int = toIntArr(book_time);
//2.
sortBookTime(book_time_int);
//3.
answer=calcMinRoom(book_time_int);
return answer;
}
//1. StringArr -> intArr. 이 때 퇴실시간 +10해서 저장하되, 더한 값이 60분 이상이라면, +100 -60
private int[][] toIntArr(String[][] arr){
int size = arr.length;
int[][] newArr = new int[size][2];
for(int i=0; i<size; i++){
newArr[i][0] = Integer.parseInt(arr[i][0].replace(":",""));
newArr[i][1] = Integer.parseInt(arr[i][1].replace(":",""))+10;
if(newArr[i][1]%100>=60){
newArr[i][1]+=(100-60);
}
}
return newArr;
}
//2. 입실시간 기준 오름차순 정렬. 이 때, 두 요소의 입실시간이 같다면 다음 기준은 퇴실시간으로.
private void sortBookTime(int[][] arr){
Arrays.sort(arr, (a,b)->{
if(a[0] > b[0]){
return 1;
}
else if(a[0]<b[0]){
return -1;
}
else{
if(a[1]>b[1]){
return 1;
}else{
return -1;
}
}
});
}
//3. PriorityQueue사용, 요소는 퇴실시간+10으로 한다. 모든 예약타임을 pq의 peek와 비교하며 현재 입실시간이 peek보다 크거나 같다면 pq.poll() 및 add/ 반대라면 only add
private int calcMinRoom(int[][] arr){
PriorityQueue<Integer> occupied = new PriorityQueue<>();
for(int[] time : arr){
if(occupied.size()==0){
occupied.add(time[1]);
continue;
}
int earliestCheckout=occupied.peek();
if(time[0] >= earliestCheckout){
occupied.poll();
}
occupied.add(time[1]);
}
return occupied.size();
}
}
- String[][]을 int[][]로 변환하기 위해 replace() 메서드 활용
- 시간 단위 유지하기 위해 60분 초과 시 +100분 -40분 연산
- 변환한 int[][]을 정렬. 이 때 각 요소의 첫번째 요소 즉, 입실 시간을 기준으로 오름차순 정렬하되 입실 시간이 같을 경우 퇴실시간이 빠른 순으로 정렬. Array.sort()의 매개변수로 람다식 삽입하여 구현 가능.
- PriorityQueue사용. 요소로 퇴실시간이 들어가며 다음 입실시간과 pq의 peek비교, 입실시간이 peek보다 늦으면 poll.
정답 코드2
import java.util.*;
class Solution {
class Book{
public Book(int start_time, int end_time) {
this.start_time = start_time;
this.end_time = end_time;
}
int start_time,end_time;
}
List<Book> bookList=new ArrayList<>();
int toMinute(String time){
StringTokenizer stk=new StringTokenizer(time,":");
int hour=Integer.parseInt(stk.nextToken());
int minute=Integer.parseInt(stk.nextToken());
return hour*60+minute;
}
public int solution(String[][] book_times) {
for(String[] book_time:book_times){
int start_time=toMinute(book_time[0]);
int end_time=toMinute(book_time[1]);
bookList.add(new Book(start_time,end_time));
}
// 시작 시간대로 정렬
Collections.sort(bookList,(o1,o2)->{
if(o1.start_time==o2.start_time) return o1.end_time-o2.end_time;
else return o1.start_time-o2.start_time;
});
// 리스트를 방문하며 몇개가 필요할지 체크
List<Integer> endTimeList=new ArrayList<>();
for(Book book:bookList){
boolean isOk=false;
for(int i=0;i<endTimeList.size();i++){
// 정리시간 10분
int endTime=endTimeList.get(i)+10;
// check
if(book.start_time>=endTime) {
// 예약 시간 넣고 업데이트
endTimeList.set(i,book.end_time);
isOk=true;
break;
}
}
// 아무 방도 넣지 못하면 새로운 방 추가
if(!isOk) endTimeList.add(book.end_time);
}
return endTimeList.size();
}
}
- 예약시간의 입실시간과 퇴실시간을 필드로 갖는 내부 클래스 Book 선언
- 문자열로 주어진 시, 분을 분 단위로 통일하기 위한 toMinute메서드 정의
- 주어진 String[][]을 돌며 StringTokenizer사용하여 입실 시간과 퇴실시간을 Book객체에 대입, BookList에 add
- bookList 입실시간 순으로 sort. 이 때 Collections.sort()사용하는데 입실시간이 같으면 퇴실시간으로 정렬하기 위해 람다식 매개변수 사용.
정렬된 bookList돌며 조건에 부합하는 경우 endTimeList에 현재요소 add - endTimeList의 최종 size반환
새로 알게된 사실
Arrays.sort(), Collections.sort() 사용 시 람다식 사용해서 세부 정렬 방법 정의. 해당 람다식은 함수형 인터페이스 Comparator를 구현한 익명 구현 객체이다.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Comparator.html
참고 블로그: https://ifuwanna.tistory.com/328
split과 StringBuilder사용해 복잡하게 구현하는 대신 replace혹은 StringTokenizer를 사용하자
참고 블로그: https://123okk2.tistory.com/427
자료구조 문제가 아니더라도 다양한 Collection자료구조 사용하면 쉽게 해결가능하더라.. 연습을 통해 여러 자료구조에 대해 더 자세히 알아서 새로운 문제 풀 때 떠올릴 수 있도록 하자.
그리고 내부 클래스를 사용하는 아이디어도 한번쯤 떠올려 보자.
'Algorithm > 그리디' 카테고리의 다른 글
| [Java] 백준 1931 - 회의실 배정 (0) | 2023.12.12 |
|---|---|
| [Java] 프로그래머스 - 요격 시스템 (0) | 2023.12.12 |
| [Java] 프로그래머스 - 마법의 엘리베이터 (1) | 2023.04.28 |
| [Java] 백준 2217 - 로프 (0) | 2023.04.08 |
| 프로그래머스 Lv.1 - 명예의 전당 (1) 파이썬 풀이 (0) | 2022.12.24 |