안녕하세요

프로그래머스 JS [줄 서는 방법] 본문

프로그래머스/Lv.2

프로그래머스 JS [줄 서는 방법]

sakuraop 2022. 12. 29. 03:56

줄 서는 방법

문제 설명

n명의 사람이 일렬로 줄을 서고 있습니다. n명의 사람들에게는 각각 1번부터 n번까지 번호가 매겨져 있습니다. n명이 사람을 줄을 서는 방법은 여러가지 방법이 있습니다. 예를 들어서 3명의 사람이 있다면 다음과 같이 6개의 방법이 있습니다.

  • [1, 2, 3]
  • [1, 3, 2]
  • [2, 1, 3]
  • [2, 3, 1]
  • [3, 1, 2]
  • [3, 2, 1]

사람의 수 n과, 자연수 k가 주어질 때, 사람을 나열 하는 방법을 사전 순으로 나열 했을 때, k번째 방법을 return하는 solution 함수를 완성해주세요.

제한사항
  • n은 20이하의 자연수 입니다.
  • k는 n! 이하의 자연수 입니다.

입출력 예nkresult
3 5 [3,1,2]

 


문제 설명

순열을 직접 다 생성하게 되면 O(N!) 이라는 공간복잡도로 인해서 
n=3 일 때 3! = 6 가지
n=4 일 때 4! = 24 가지
n=20 일 때 2432902008176640000이 되므로 순열을 직접 만들고 정렬하여 구하는 방식은 아니다.

  • k가 1일 때 [1, 2, 3]
  • k가 2일 때 [1, 3, 2]
  • k가 3일 때 [2, 1, 3]
  • k가 4일 때 [2, 3, 1]
  • k가 5일 때 [3, 1, 2]
  • k가 6일 때 [3, 2, 1]
이를 만들 수 있는 규칙을 찾아야 한다.

k가 1,2일 때는 숫자 배열에서 1 골라냄
k가 3,4일 때는 숫자 배열에서 2 골라냄
k가 5,6일 때는 숫자 배열에서 3 골라냄

그리고 남은 숫자들은 2! 의 경우의 수를 가져
k가 0또는 1이 되어 두 가지 중 하나를 선택할 수 있도록 하면 될 것 같다.

숫자를 골라낼 때마다 짧아지는 배열의 길이와
이 외에 계속해서 변하는 수 k사이에 적절한 규칙을 만들어 내면 
n!에 대해서 몇 번째 숫자를 골라낼지 구할 수 있겠다.


3!일 때 k는 2씩 커질 때마다 첫번째 자릿수가 변하고,
4!일 때 k는 6씩 커질 때마다 첫번째 자릿수가 변한다.

2와 6은 각각 2!, 3! 인 것을 유추할 수 있다.

n! / n 에 대입하면 구해진다.

  • k가 2일 때 [1, 3, 2]
  • k가 3일 때 [2, 1, 3]
자릿수를 정하는 수를 구하고 (n! / n) 
=> range /= numberArray.length

k가 3일 때 [2,1,3]을 만들려면 2를 골라내야 하는데 인덱스는 0부터 시작하므로 k-1을 해준다.
=> .splice(Math.floor((k - 1) / range), 1)

첫번째 자릿수를 구했으므로, 두번째 자릿수를 구하기 위해 k 나머지 남은 숫자에 대해 시행할 수 있도록 한다.
=> k = k % range;




이해 안되는 테스트 케이스 (4번, 14번)
원래는 습관적으로 parseInt로 구하려 했다. 
parseInt((k - 1) / range
그런데 아무리 안되는 부분을 뒤져봐도 안되길래 검색을 하였더니 floor의 경우에는 통과하더라.

Math
.floor((k - 1) / range

자연수이기 때문에 상관이 없지 않은가 싶어 테스트 케이스를 열어보고 싶다.

function
solution(n, k) {
    const resultArray = [];
    const numberArray = Array(n)
        .fill()
        .map((_, index) => index + 1);
    let range = numberArray.reduce((accumulator, currentValue) => accumulator * currentValue, 1);

    while (resultArray.length < n) {
        range /= numberArray.length;
        resultArray.push(...numberArray.splice(Math.floor((k - 1) / range), 1));
        k = k % range;
    }

    return resultArray;
}