본문 바로가기
코딩 테스트/백준

1422 숫자의 신 (자바스크립트)

by 위그든씨 2025. 6. 13.

숫자의 신은 여러명이 있지만, 그 중에 자연수의 신은 오세준이다. 오세준은 자연수의 신으로 오래오래 살다가 어느 날 음수의 신과 전쟁을 하게 되었다. 오세준은 음수의 신 이다솜을 이기기위해서 큰 숫자를 만들기로 했다.

오세준은 지금 K개의 자연수를 가지고 있다. 오세준은 K개의 수 중에 정확하게 N개의 수를 뽑아내서 그 수를 붙여서 만들 수 있는 수중에 가장 큰 수를 만들고자 한다. 같은 수를 여러 번 이용해도 된다. 단, 모든 수는 적어도 한 번은 이용되어야 한다.

오세준이 현재 가지고 있는 K개의 수가 주어졌을 때, 이 수를 적어도 한 번 이상 이용해서 만들 수 있는 수 중에 가장 큰 수를 출력하는 프로그램을 작성하시오.

예를 들어 지금 오세준이 2, 3, 7 이라는 3개의 수를 가지고 있고, 4개의 수를 뽑아야 한다면, 7732를 만들면 가장 큰 수가 된다.

입력

첫째 줄에 K와 N이 공백을 사이에 두고 주어진다. K와 N은 각각 50보다 작거나 같은 자연수이고, N은 K보다 크거나 같다. 둘째 줄에는 K개의 수가 한 줄에 하나씩 주어진다. 각 수는 1,000,000,000보다 작거나 같은 자연수이다. 이 수는 중복되어 들어올 수 있다. 만약 중복되어서 들어오는 경우에는 각 수가 적어도 입력으로 주어진 만큼 이용되어야 한다는 소리다.

출력

N개의 수를 뽑아서 연결해서 만들 수 있는 가장 큰 수를 출력한다.

=====

문제 풀이

최대 수를 출력하기 위해선 우선 가장 큰 수를 n-k 만큼 세워둔다.

세워두는 것은 stack 이라는 배열에 넣을 것이다. 이제 큰 수를 하나씩 끄집어내서 stack에 각 자리에 넣어보며 더 큰 수를 만들면 된다.

각 자리에 넣어보면서 큰 수를 만드는 과정은 이진 탐색으로 진행하였다.

특정 중간 인덱스를 기준으로 그 값과 넣어야 할 값으로 만들 수 있는 두 값을 비교하여 pivot을 뒤에 놨을 떄 더 큰 값이 됐다면 넣어야 할 값을 앞으로 더 보내도 되는 것이니 e=mid-1 , pivot을 앞으로 놨을 때 더 작다면 뒤로 보내도 되는거니 s-mid+1을 두어 최종적으로 s가 있을 곳이 value를 넣을 자리이다.

큰 수대로 하나씩 끄집어내는 것을 힙큐로 동작시켰는데 그냥 입력 배열을 오름차순으로 한 뒤 하나씩 pop 하면 됐겠다 싶다.

정답 코드

class Heapq {
    hq;
    constructor() {
        this.hq = [undefined];
    }
    isExist() {
        return this.hq.length > 1;
    }
    swap(src, des) {
        [this.hq[src], this.hq[des]] = [this.hq[des], this.hq[src]];
    }
    isSmall(src, target) {
        if (this.hq[src][0] < this.hq[target][0]) {
            return true;
        }
        return false;
    }
    size() {
        return this.hq.length;
    }
    push(arr) {
        this.hq.push(arr);
        let cur = this.size() - 1;
        while (cur > 1) {
            const parent = Math.floor(cur / 2);
            if (this.isSmall(cur, parent)) {
                this.swap(cur, parent);
                cur = parent;
            } else {
                break;
            }
        }
    }
    pop() {
        if (!this.isExist()) return undefined;
        const root = this.hq[1];
        const tale = this.hq.pop();
        if (!this.isExist()) return root;
        this.hq[1] = tale;
        let cur = 1;
        while (cur * 2 < this.size()) {
            let smallest = cur * 2;
            if (smallest + 1 < this.size()) {
                if (this.isSmall(smallest + 1, smallest)) {
                    smallest += 1;
                }
            }
            if (this.isSmall(smallest, cur)) {
                this.swap(smallest, cur);
                cur = smallest;
            } else {
                break;
            }
        }
        return root;
    }
    firstNumberOfRoot() {
        if (!this.isExist()) return false;
        return String(this.hq[1][0])[1];
    }
}

const input = require('fs')
    .readFileSync(process.platform === 'linux' ? '/dev/stdin' : './input.txt')
    .toString()
    .trim()
    .split('\n');

const [n, m] = input[0].split(' ').map(Number);
const nums = input.slice(1).map(Number);

const hq = new Heapq();

for (const v of nums) {
    hq.push([-1 * v]);
}

let diff = m - n;
const stack = [];

while (diff > 0) {
    const [v] = hq.pop();
    const num = v * -1;
    stack.push(num);
    hq.push([v]);
    diff--;
}

const binary = (value) => {
    let s = 0;
    let e = stack.length - 1;
    const strValue = String(value);
    const a = strValue[0];

    while (s <= e) {
        const mid = Math.floor((s + e) / 2);
        const strNumOfMid = String(stack[mid]);

        const aa = Number(strValue + strNumOfMid);
        const bb = Number(strNumOfMid + strValue);
        if (aa > bb) {
            e = mid - 1;
        } else {
            s = mid + 1;
        }
    }
    return s;
};

while (hq.isExist()) {
    const v = hq.pop()[0] * -1;
    const idx = binary(v);
    stack.splice(idx, 0, v);
}

console.log(stack.join(''));

 

'코딩 테스트 > 백준' 카테고리의 다른 글

10021 Watering the Fields  (0) 2025.06.18
10830 행렬 제곱 (자바스크립트)  (0) 2025.06.14
2638 치즈 (자바스크립트)  (0) 2025.06.10
5676 음주 코딩 (파이썬)  (0) 2025.06.09
2585 경비행기 (자바스크립트)  (0) 2025.06.04