문제 소개
이번 글에서는 첫 번째 인수로 숫자 num을, 두 번째 인수로 숫자 parts를 받는 JavaScript 함수를 작성해 보겠습니다.
이 함수는 num을 정확히 parts개의 숫자로 나누어야 하며, 다음 두 가지 조건을 만족해야 합니다.
- 나눠진 숫자들은 서로 최대한 가까운 값이어야 합니다.
- 가능한 한 균등하게 나누어야 합니다.
결과 배열에서 숫자들의 순서는 중요하지 않습니다.
예를 들어, 함수에 다음과 같은 입력이 주어졌다고 가정해 보겠습니다.
입력
const num = 20;
const parts = 6;
출력
const output = [3, 3, 3, 3, 4, 4];
20을 6으로 나누면 몫은 3이고 나머지는 2입니다. 따라서 기본 값인 3 네 개에 나머지 2를 분배해 4 두 개를 만들어 [3, 3, 3, 3, 4, 4]라는 결과를 얻을 수 있습니다. 모든 숫자의 차이가 1을 넘지 않으므로 '서로 최대한 가까운' 조건을 충족합니다.
구현 예제
다음은 이 문제를 해결하는 전체 코드입니다.
const num = 20;
const parts = 6;
const splitNumber = (num = 1, parts = 1) => {
let n = Math.floor(num / parts);
const arr = [];
for (let i = 0; i < parts; i++){
arr.push(n);
};
if(arr.reduce((a, b) => a + b, 0) === num){
return arr;
};
for(let i = 0; i < parts; i++){
arr[i]++;
if(arr.reduce((a, b) => a + b, 0) === num){
return arr;
};
};
};
console.log(splitNumber(num, parts));
코드 동작 원리
함수의 동작 과정을 단계별로 살펴보겠습니다.
- 기본 값 계산:
Math.floor(num / parts)를 사용해 num을 parts로 나눈 몫의 정수 부분을 구합니다. 위 예제에서는Math.floor(20 / 6)의 결과인 3이 됩니다. - 배열 초기화: 구한 몫 n을 parts개만큼 배열에 채워 넣습니다. 이 시점에는 [3, 3, 3, 3, 3, 3] 배열이 생성됩니다.
- 합 검증:
reduce()메서드로 배열 요소의 총합을 계산해 num과 일치하는지 확인합니다. 일치한다면 나눗셈이 딱 떨어지는 경우이므로 배열을 그대로 반환합니다. - 나머지 분배: 총합이 num보다 작다면, 배열의 앞쪽 요소부터 하나씩 1을 더하고 매번 총합을 다시 확인합니다. 총합이 num에 도달하는 순간 해당 배열을 반환하며, 이렇게 하면 각 숫자 간의 차이가 최대 1로 유지됩니다.
실행 결과
[ 4, 4, 3, 3, 3, 3 ]
출력 결과를 보면 20이 3과 4로만 구성된 여섯 개의 숫자로 나뉘었습니다. 각 숫자의 차이가 1을 넘지 않으므로 '서로 최대한 가까운 값'이라는 조건을 완벽하게 충족합니다. 이 접근 방식은 결제 금액 분할, 리소스 균등 배분 등 실무에서도 유용하게 활용할 수 있습니다.