문제 설명
점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.
전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.
제한사항
- 전체 학생의 수는 2명 이상 30명 이하입니다.
- 체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
- 여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
- 여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.
- 여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정 하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.
생각
거의 어거지로 푼 문제다.. 일단 체육복을 도난 당한 학생과 여벌로 가져온 학생이 겹치면 그 학생은 더 이상 빌려줄 수 없으므로 번호를 지워주는 것 부터 시작한다. 그런 학생이 있다면 번호를 -1로 바꿔 더 이상 빌려줄 수 없게 만든다.
후에 도난당한 학생의 앞 뒤번호의 학생이 여벌 옷을 가지고 있다면 학생에게 옷을 빌려주고 여벌의 옷을 가진 학생은 -1로 만들어 뒤의 학생에게 빌려줄 수 없는 상태로 만든다.
예를 들어 체육복을 잃어버린 학생은 [1,3,5] 번 학생이다. 그리고 여벌 옷을 가지고 있는 학생은 [2,4,5] 번이라고 하자.
먼저 여벌의 옷을 가지고 있는 학생이 도난당한 경우를 검사한다. 5번 학생의 여벌 옷을 가지고 있지만 도난 당했으므로 둘다 -1로 만들어 없는 상태로 만든다.
2번 학생은 자신의 앞 번호인 1번에게 체육복을 빌려 줄 수 있다. 그 후에 2번 학생을 -1로 만들어 뒤의 학생에게 빌려 줄 수 없는 상태로 만들어야한다. 마찬가지로 4번 학생도 3번 학생에게 체육복을 빌려주고 -1이 된다.
답은 answer = (전체 학생수) 5 - (도난당한 학생 수) 3 + (도난 당한 학생중 여벌 옷을 가지고 있던 학생 수) 1
+ (다른 학생으로부터 체육복을 받은 학생 수) 2 = 5가 된다.
코드
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 32 33 34 35 | class Solution { public int solution(int n, int[] lost, int[] reserve) { int answer = 0; int lost1 = 0; int count = 0; //여벌 옷을 가지고 있는 학생이 도난 당하면 빌려줄 수 없도록 만든다. for(int i=0; i<lost.length; i++) { for(int j=0; j<reserve.length; j++) { if(lost[i]==reserve[j]) { lost1++; lost[i] = -1; reserve[j] = -1; break; } } } //옷을 빌려주고 -1로 만들어 뒤의 학생에게 빌려주지 않게 한다. for(int i=0; i<lost.length; i++) { for(int j=0; j<reserve.length; j++) { if(lost[i]==reserve[j]+1 || lost[i]==reserve[j]-1) { count++; reserve[j] = -1; break; } } } //answer은 전체 학생수에서 잃어버린 학생 수를 뺀다. //후에 여벌옷을 가진 학생이 도난 당했으면 그 수만큼 더해주고 옷을 빌려준 학생 수 만큼 다시 더해준다. answer = n - lost.length + lost1 + count; return answer; } } | cs |
생각보다 푸는데 조금 오래걸렸다! 끼워맞추기로 푼 것 같아 부끄럽다..
변수의 의미를 확실하게 할 수 있는 네이밍을 해야겠다.
추가
카테고리에 탐욕법이라고 적혀 있는데 문제를 풀 때 전혀 신경쓰지 않았지만 글을 쓰며 궁금해졌다.
개인적으로 최적의 해를 구하기는 어렵지만 각각의 상황에서 최선을 다한다(?)라는 의미로 알고있는데 한번 찾아보도록하자.
탐욕 알고리즘 (greedy algorithm)
최적해를 구하는 데에 사용되는 근사적인 방법으로, 여러 경우 중 하나를 결정해야 할 때마다 그 순간에 최적이라고 생각되는 것을 선택해 나가는 방식으로 진행하여 최종적인 해답에 도달한다. 순간마다 하는 선택은 그 순간에 대해 지역적으로는 최적이지만, 그 선택들을 계속 수집하여 최종적(전역적)인 해답을 만들었다고 해서, 그것이 최적이라는 보장은 없다. [출처: 위키백과]
내 생각과 맞아서 꽤나 뿌듯했다. 나중에 알고리즘 중 동적계획법과 함께 최적해를 구하는데 쓰인다는데, 어서 알고리즘을 더 배워 동적계획법에 대해서도 공부하고 싶다.
'알고리즘 > 코딩 - 프로그래머스' 카테고리의 다른 글
[Java][프로그래머스][Level 1] 같은 숫자는 싫어! (0) | 2019.03.24 |
---|---|
[Java][프로그래머스][Level 1] 가운데 글자 가져오기 (0) | 2019.03.24 |
[Java][프로그래머스][Level 1] 2016년 (0) | 2019.03.24 |
[Java][프로그래머스][Level 1] K번째 수 (0) | 2019.03.24 |
[Java][프로그래머스][Level 1] 모의고사 (0) | 2019.03.24 |