알고리즘 문제 풀기

백준 10973: 이전 순열 - javascript(구현)

Fo_rdang 2024. 3. 13. 19:58
반응형

문제 출처 

https://www.acmicpc.net/problem/10973

 

10973번: 이전 순열

첫째 줄에 입력으로 주어진 순열의 이전에 오는 순열을 출력한다. 만약, 사전순으로 가장 처음에 오는 순열인 경우에는 -1을 출력한다.

www.acmicpc.net

문제

1부터 N까지의 수로 이루어진 순열이 있다. 이때, 사전순으로 바로 이전에 오는 순열을 구하는 프로그램을 작성하시오.

사전 순으로 가장 앞서는 순열은 오름차순으로 이루어진 순열이고, 가장 마지막에 오는 순열은 내림차순으로 이루어진 순열이다.

N = 3인 경우에 사전순으로 순열을 나열하면 다음과 같다.

  • 1, 2, 3
  • 1, 3, 2
  • 2, 1, 3
  • 2, 3, 1
  • 3, 1, 2
  • 3, 2, 1

입력

첫째 줄에 N(1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄에 순열이 주어진다.

출력

첫째 줄에 입력으로 주어진 순열의 이전에 오는 순열을 출력한다. 만약, 사전순으로 가장 처음에 오는 순열인 경우에는 -1을 출력한다.

예제 입력 1 복사

4
1 2 3 4

예제 출력 1 복사

-1

예제 입력 2 복사

5
5 4 3 2 1

예제 출력 2 복사

5 4 3 1 2

문제 풀이 힌트 

주어진 수를 가지고 이전 순열을 찾는 규칙을 알아내보자. 

 

[i-1] > [i] 인 값을 뒤에서 부터 찾는다. 

1,2,3,4  => 없다. 그러니 -1로 리턴한다. 

1,2,4,3  => 4랑 3이 된다. `이 두 수를 뒤집으면 이전 순열이 된다.`

1,3,2,4  => 3이랑 2가 된다. `이 두수를 뒤집은 후 i 이후의 수를 내림차순 하면 이전 순열이 된다.`

1,3,4,2  => 4랑 2가 된다. `이 두 수를 뒤집으면 이전 순열이 된다.`

1,4,2,3  => 4랑 2가 된다. `4를 기준으로 오른쪽에서 가장 큰 값을 고른다. 대신 4보단 작아야 한다. 그 수랑 교환후, i 이후의 수를 내림차순 하면 된다.`

1,4,3,2  => 3이랑 2가 된다. `이 두수를 뒤집으면 이전 순열이 된다.`

 

여기서 모든 규칙을 포괄하는 건. 

 `[i] > [i-1] 인 수를 구하고, [i]를 기준으로 오른쪽에서 가장 큰 값을 고른다. 대신 [i] 값보단 작아야 한다. 그 수랑 위치 교환후, i 이후의 수를 내림차순 하면 된다.`

문제 풀이 코드 

const input = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
const n = parseInt(input[0]);
const permutation = input[1].split(' ').map(v => +v);

function findPrevPermutation(permutation) {
    const n = permutation.length;
    let i = n - 1;
    
    while (i > 0 && permutation[i - 1] <= permutation[i]) {
        i--;
    }
    
    if (i <= 0) {
        return "-1";
    }
    
    let j = n - 1;
    while (permutation[j] >= permutation[i - 1]) {
        j--;
    }
    [permutation[i - 1], permutation[j]] = [permutation[j], permutation[i - 1]];
    
    let k = n - 1;
    while (i < k) {
        [permutation[i], permutation[k]] = [permutation[k], permutation[i]];
        i++;
        k--;
    }
    return permutation.join(' ');
}

console.log(findPrevPermutation(permutation));

의사 코드 추가 

// 입력을 읽어옵니다.
const input = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
// 순열의 길이를 파싱합니다.
const n = parseInt(input[0]);
// 순열을 배열로 변환합니다.
const permutation = input[1].split(' ').map(v => +v);

// 이전 순열을 찾는 함수를 정의합니다.
function findPrevPermutation(permutation) {
    const n = permutation.length; // 순열의 길이를 저장합니다.
    let i = n - 1; // 마지막 요소부터 시작하여 탐색할 인덱스를 설정합니다.

    // 오름차순으로 정렬된 마지막 요소부터 역순으로 탐색합니다.
    while (i > 0 && permutation[i - 1] <= permutation[i]) {
        i--;
    }

    // 순열이 가장 작은 순열인 경우
    if (i <= 0) {
        return "-1"; // -1을 반환합니다.
    }

    let j = n - 1; // 순열을 역순으로 탐색할 인덱스를 설정합니다.
    // i 위치의 바로 앞에 있는 값보다 큰 값을 찾습니다.
    while (permutation[j] >= permutation[i - 1]) {
        j--;
    }
    // i 위치의 값과 j 위치의 값을 교환합니다.
    [permutation[i - 1], permutation[j]] = [permutation[j], permutation[i - 1]];

    let k = n - 1; // 뒤집을 범위의 끝 인덱스를 설정합니다.
    // i부터 k까지의 순열을 뒤집습니다.
    while (i < k) {
        [permutation[i], permutation[k]] = [permutation[k], permutation[i]]; // 교환합니다.
        i++; // 시작 인덱스를 증가시킵니다.
        k--; // 끝 인덱스를 감소시킵니다.
    }
    return permutation.join(' '); // 결과 순열을 문자열로 반환합니다.
}

// 이전 순열을 출력합니다.
console.log(findPrevPermutation(permutation));
반응형