해당 문제는 문제가 이상? 한 느낌이 없지않아 있는데요. 최대 이익이라고 하는데 곱하는건 최소값을 곲하니... 음.... 뭘까요... 아무튼 문제 설명에서 이상하긴 한데 그래도 풀어내긴 했습니다.
문제를 설명해 드리면 과일 박스에서 등급이 높은 것부터 작은 상자(배열 속 배열)에 담은 후 배열 길이만큼 for문을 돌리는데, 이때 박스 당(배열 속 배열들) 사과의 개수(m)를 충족하지 않는 때, 즉 박스 당 사과가 개수만큼 꽉 찼다면 그 중 가장 작은 등급을 사과의 개수랑 곱해서 박스 당 최대 이익을 획득하는 방법입니다.
근데 다시봐도 이게 왜 최소 등급으로 구한 값이 최대 이익인지.... 흠.... 아무튼...
이번에는 코드가 그리 복잡하지 않아서 자세한 그림 설명은 생략하고, 자바스크립트 코드 버전을 바로 보여드리겠습니다!
- 자바스크립트 버전
function solution(k, m, score) { // 사과들을 담은 박스들을 보관할 배열 appleArr = [] // 큰 값(등급) 대로 나오도록 정렬 score.sort((a,b) => b-a); // 반복문을 도는데 i의 증가값 조건을 m만큼 누적 합산합니다. 얘를 들어 i가 0이면 slice는 0,3 즉 0부터 2까지 3개(m의 개수)를 자르고 난 후 i는 3이 됩니다. 다음 for문에서는 i가 3이므로 3, 6(3)까지 3개를 자르고 또 반복을 하죠. 이런 식으로 배열의 요소를 m만큼 잘라서 appleArr에 반환할 수 있는 것입니다. (남는 사과 자리가 있는 박스라면 어차피 배열의 끝까지를 반환하므로 혼자 남든 하겠죠.) for (let i = 0; i < score.length; i += m) { appleArr.push(score.slice(i, i + m)); } //각 사과 박스 당 최대 이익을 누적 합산시킬 변수 let count = 0; // 반복문을 다시 돌리면서 만약 상자 당 사과 개수가 충족되어야 할 사과 개수(m)를 충족하지 못하면 제외하고, 그게 아니라면 맨 사과 당 등급이 낮은 사과 등급(각 배열의 맨 끝자리)을 사과 개수(m) 만큼 곱하여 각각 누적 for(let i = 0; i < appleArr.length ; i++){ if(appleArr[i].length != m) continue; count += appleArr[i][m-1] * m; } // 반환된 count 반환 return count; }
그리고 자바 버전으로 구현한 코드는 다음과 같습니다.
- 자바 버전
import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; class Solution { public int solution(int k, int m, int[] score) { int answer = 0; // int 배열을 Integer 배열로 변환하여 내림차순으로 정렬합니다. 이유는 Arrays.sort의 경우 기본 타입은 오름차순만 정렬할 수 있기 때문에 컬렉션의 sort 메서드에 reverseOrder를 매개변수로 넣어 역방향 정렬을 하려면 int형으로 되어있는 score의 변수를 Integer형 배열인 scoreInteger 배열에 담은 후 정렬 처리해줘야 합니다. Integer[] scoreInteger = new Integer[score.length]; for (int i = 0; i < score.length; i++) { scoreInteger[i] = score[i]; } Arrays.sort(scoreInteger, Collections.reverseOrder()); // 조건을 scoreInteger.length - m(개수)로 준 이유는, for문을 0부터 돌면서 사과 개수 - 1(인덱스 기준)을 한 위치, 그러니까 내림차순 정렬된 배열에서 각각의 박스(m)의 최저 품질 사과를 선택하여 연산을 한 뒤 i값을 m만큼 증가시켜야 그 다음 for문에는 다음 박스의 최저 품질의 사과를 계속 연산에 포함할 수 있고, 또한 i가 0부터 시작해 m만큼 늘어나는 만큼 for문 마다 딱 사과 개수 만큼 돌 수 있기 때문에 마지막에 남는 사과는 자연스럽게 포함시키지 않을 수 있기 때문입니다. for (int i = 0; i <= scoreInteger.length - m; i += m) { answer += scoreInteger[i + m - 1] * m; } return answer; } }
JS의 경우에 배열의 정렬을 오름차순이든 내림차순이든 아주 쉽게 할 수 있지만, 자바의 경우 sort 연산자를 사용할 때 객체 매개변수의 두번째에는 내림차순을 사용하기 위해 Comparator를 구현한 메서드를 전달해야 하는데요. 대표적인 메서드는 Collections.reverseOrder() 메서드인데, 이 메서드가 할당 될 경우 sort의 첫번째 매개변수는 기본 타입을 지정하는 것이 불가능 합니다. (Comparator 자체가 Integer를 받기로 되어 있음)
그래서 기존의 int형 배열 score를 Integer형 배열로 변환하여 값들을 담고, for문으로 하나 하나 담아야만 했습니다. (물론 스트림을 써도 되긴 하는데 제가 거기까지는 아직... ㅎ...)
JS에서의 for문을 사용할때는 배열 안에 배열, 그러니까 사과 개수만큼 묶어 놓은 상자들의 배열을 만들어(2중 배열) for문 만큼 돌렸는데, 자바에서는 좀 더 색다른 방법을 사용했습니다. 자바 for문에 주석으로 설명을 달긴 했지만, 이 부분은 여러분들이 한 번 직접 for문이 돌아가는 과정을 세어보시면 왜 저렇게 코드를 짜보았는지 이해하시리라 생각됩니다.
물론 JS의 방법보다 간결하고 효율성에서도 낫다고 보기 때문에 연습에 도움이 되었던 코드였다고 생각합니다.