개발팀 내에서 이벤트 개발을 담당하고 있는 무지는 최근 진행된 카카오이모티콘 이벤트에 비정상적인 방법으로 당첨을 시도한 응모자들을 발견하였습니다. 이런 응모자들을 따로 모아 불량 사용자라는 이름으로 목록을 만들어서 당첨 처리 시 제외하도록 이벤트 당첨자 담당자인 프로도 에게 전달하려고 합니다. 이 때 개인정보 보호을 위해 사용자 아이디 중 일부 문자를 ’’ 문자로 가려서 전달했습니다. 가리고자 하는 문자 하나에 ’’ 문자 하나를 사용하였고 아이디 당 최소 하나 이상의 ’*’ 문자를 사용하였습니다.
무지와 프로도는 불량 사용자 목록에 매핑된 응모자 아이디를 제재 아이디 라고 부르기로 하였습니다.
예를 들어, 이벤트에 응모한 전체 사용자 아이디 목록이 다음과 같다면
| 응모자 아이디 | 
|---|
| frodo | 
| fradi | 
| crodo | 
| abc123 | 
| frodoc | 
다음과 같이 불량 사용자 아이디 목록이 전달된 경우,
| 불량 사용자 | 
|---|
| frd | 
| abc1** | 
불량 사용자에 매핑되어 당첨에서 제외되어야 야 할 제재 아이디 목록은 다음과 같이 두 가지 경우가 있을 수 있습니다.
| 제재 아이디 | 
|---|
| frodo | 
| abc123 | 
| 제재 아이디 | 
|---|
| fradi | 
| abc123 | 
이벤트 응모자 아이디 목록이 담긴 배열 userid와 불량 사용자 아이디 목록이 담긴 배열 bannedid가 매개변수로 주어질 때, 당첨에서 제외되어야 할 제재 아이디 목록은 몇가지 경우의 수가 가능한 지 return 하도록 solution 함수를 완성해주세요.
user_id 배열 각 원소들의 값은 길이가 1 이상 8 이하인 문자열입니다.
banned_id 배열 각 원소들의 값은 길이가 1 이상 8 이하인 문자열입니다.
| user_id | banned_id | result | 
|---|---|---|
["frodo", "fradi", "crodo", "abc123", "frodoc"] | 
["fr*d*", "abc1**"] | 
2 | 
["frodo", "fradi", "crodo", "abc123", "frodoc"] | 
["*rodo", "*rodo", "******"] | 
2 | 
["frodo", "fradi", "crodo", "abc123", "frodoc"] | 
["fr*d*", "*rodo", "******", "******"] | 
3 | 
function solution(user_id, banned_id) {
    const answer = new Set()
    const ch = new Array(user_id.length).fill(0)
    const dis = new Array(banned_id.length).fill(0)
    
    function DFS(L){
        if (L === banned_id.length){
            answer.add(dis.concat().sort().join(''))
        }
        else {
            for (let i=0; i<user_id.length; i++){
                if (!ch[i]){
                    if (user_id[i].length === banned_id[L].length){
                        let alpha_cnt = 0
                        let star_cnt = 0
                        for (let j=0; j<user_id[i].length; j++){
                            if (banned_id[L][j] === '*'){
                                star_cnt += 1
                            } else if (banned_id[L][j] === user_id[i][j]){
                                alpha_cnt += 1
                            }
                        }
                        if (alpha_cnt + star_cnt === user_id[i].length){
                            ch[i] = 1
                            dis[L] = i
                            DFS(L+1)
                            ch[i] = 0
                        }    
                    }
                }
            }
        }
    }
    
    DFS(0)
    return answer.size
}하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다.
예를들어
- 0ms 시점에 3ms가 소요되는 A작업 요청
- 1ms 시점에 9ms가 소요되는 B작업 요청
- 2ms 시점에 6ms가 소요되는 C작업 요청와 같은 요청이 들어왔습니다. 이를 그림으로 표현하면 아래와 같습니다.

한 번에 하나의 요청만을 수행할 수 있기 때문에 각각의 작업을 요청받은 순서대로 처리하면 다음과 같이 처리 됩니다.

- A: 3ms 시점에 작업 완료 (요청에서 종료까지 : 3ms)
- B: 1ms부터 대기하다가, 3ms 시점에 작업을 시작해서 12ms 시점에 작업 완료(요청에서 종료까지 : 11ms)
- C: 2ms부터 대기하다가, 12ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 16ms)이 때 각 작업의 요청부터 종료까지 걸린 시간의 평균은 10ms(= (3 + 11 + 16) / 3)가 됩니다.
하지만 A → C → B 순서대로 처리하면

- A: 3ms 시점에 작업 완료(요청에서 종료까지 : 3ms)
- C: 2ms부터 대기하다가, 3ms 시점에 작업을 시작해서 9ms 시점에 작업 완료(요청에서 종료까지 : 7ms)
- B: 1ms부터 대기하다가, 9ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 17ms)이렇게 A → C → B의 순서로 처리하면 각 작업의 요청부터 종료까지 걸린 시간의 평균은 9ms(= (3 + 7 + 17) / 3)가 됩니다.
각 작업에 대해 [작업이 요청되는 시점, 작업의 소요시간]을 담은 2차원 배열 jobs가 매개변수로 주어질 때, 작업의 요청부터 종료까지 걸린 시간의 평균을 가장 줄이는 방법으로 처리하면 평균이 얼마가 되는지 return 하도록 solution 함수를 작성해주세요. (단, 소수점 이하의 수는 버립니다)
| jobs | return | 
|---|---|
| [[0, 3], [1, 9], [2, 6]] | 9 | 
문제에 주어진 예와 같습니다.
function solution(jobs) {
    const length = jobs.length
    jobs.sort((a,b) => a[0]-b[0])
    let waitQ = [] 
    const progressQ = [] 
    let total = 0
    let cur_time = 0
    while (jobs.length>0 || waitQ.length > 0){
        if (waitQ.length > 0){
            waitQ = waitQ.map(v => ({remain: v['remain'], time: v['time']+1}))
        } // waitQ time ++
        const requests = []
        while (true){
            if (jobs.length> 0 && jobs[0][0] === cur_time){
                requests.push(jobs.shift())
            } else break
        }
        if (requests.length > 0){
            requests.forEach(v => waitQ.push({remain: v[1], time: 0}))
        }
        if (progressQ.length > 0){
            let {remain, time} = progressQ[0]
            progressQ[0]['remain'] = remain - 1
            progressQ[0]['time'] = time + 1
            if (remain-1 === 0){
                total += progressQ[0]['time']
                progressQ.shift()
                //다음 작업 찾기
                if (waitQ.length > 0){
                    waitQ.sort((a,b) => b['remain'] -a['remain'])
                    progressQ.push(waitQ.pop())
                }
            }
        }// 진행 중 작업 있다.
        else if (!progressQ.length){
            if (waitQ.length > 0){
                waitQ.sort((a,b) => b['remain']-a['remain'])
                progressQ.push(waitQ.pop())    
            }
        }
        cur_time += 1
    }
    // 큐 채워져있는지 확인해야해
    if (progressQ.length > 0){
        total += progressQ[0]['time'] + progressQ[0]['remain']
    }
    return Math.floor(total / length)
}카카오에서는 무료 셔틀버스를 운행하기 때문에 판교역에서 편하게 사무실로 올 수 있다. 카카오의 직원은 서로를 ‘크루’라고 부르는데, 아침마다 많은 크루들이 이 셔틀을 이용하여 출근한다.
이 문제에서는 편의를 위해 셔틀은 다음과 같은 규칙으로 운행한다고 가정하자.
09:00부터 총 n회 t분 간격으로 역에 도착하며, 하나의 셔틀에는 최대 m명의 승객이 탈 수 있다.09:00에 도착한 셔틀은 자리가 있다면 09:00에 줄을 선 크루도 탈 수 있다.일찍 나와서 셔틀을 기다리는 것이 귀찮았던 콘은, 일주일간의 집요한 관찰 끝에 어떤 크루가 몇 시에 셔틀 대기열에 도착하는지 알아냈다. 콘이 셔틀을 타고 사무실로 갈 수 있는 도착 시각 중 제일 늦은 시각을 구하여라.
단, 콘은 게으르기 때문에 같은 시각에 도착한 크루 중 대기열에서 제일 뒤에 선다. 또한, 모든 크루는 잠을 자야 하므로 23:59에 집에 돌아간다. 따라서 어떤 크루도 다음날 셔틀을 타는 일은 없다.
셔틀 운행 횟수 n, 셔틀 운행 간격 t, 한 셔틀에 탈 수 있는 최대 크루 수 m, 크루가 대기열에 도착하는 시각을 모은 배열 timetable이 입력으로 주어진다.
n ≦ 10t ≦ 60m ≦ 45timetable은 최소 길이 1이고 최대 길이 2000인 배열로, 하루 동안 크루가 대기열에 도착하는 시각이 HH:MM 형식으로 이루어져 있다.HH:MM은 00:01에서 23:59 사이이다.콘이 무사히 셔틀을 타고 사무실로 갈 수 있는 제일 늦은 도착 시각을 출력한다. 도착 시각은 HH:MM 형식이며, 00:00에서 23:59 사이의 값이 될 수 있다.
| n | t | m | timetable | answer | 
|---|---|---|---|---|
| 1 | 1 | 5 | [08:00, 08:01, 08:02, 08:03] | 09:00 | 
| 2 | 10 | 2 | [09:10, 09:09, 08:00] | 09:09 | 
| 2 | 1 | 2 | [09:00, 09:00, 09:00, 09:00] | 08:59 | 
| 1 | 1 | 5 | [00:01, 00:01, 00:01, 00:01, 00:01] | 00:00 | 
| 1 | 1 | 1 | [23:59] | 09:00 | 
| 10 | 60 | 45 | [23:59,23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59] | 18:00 | 
function convert(minutes){
    let hour = Math.floor(minutes / 60)
    let minute = minutes % 60
    if (hour < 10) hour = `0${hour}`
    if (minute < 10) minute = `0${minute}`
    return `${hour}:${minute}`
}
function solution(n, t, m, timetable) {
    timetable = timetable.map(v => {
        const [hour, minute] = v.split(':')
        return Number(hour)*60+Number(minute)
    })
    timetable.sort((a,b) => a-b)
    let i=1;
    let cnt = 0 // 매 버스마다 몇명 태웠는지
    let s = 0 // array queue 를 가리키는 index
    while (i<=n){
        cnt = 0
        const cur = 540 + (t * (i-1))
        if (i == n){
            let tmp_s = s
            for (let j=tmp_s; j<timetable.length; j++){
                if (timetable[j] <= cur){
                   cnt += 1
                   tmp_s += 1
                   if (cnt === m) break
               }
            }
            if (cnt+1 <= m) return convert(cur)
            else return convert(timetable[s+(m-1)]-1)
        } else {
           for (let j=s; j<timetable.length; j++){
               if (timetable[j] <= cur){
                   cnt += 1
                   s += 1
                   if (cnt === m) break
               }
           }     
        }
        i += 1
    }
}이중 우선순위 큐는 다음 연산을 할 수 있는 자료구조를 말합니다.
| 명령어 | 수신 탑(높이) | 
|---|---|
| I 숫자 | 큐에 주어진 숫자를 삽입합니다. | 
| D 1 | 큐에서 최댓값을 삭제합니다. | 
| D -1 | 큐에서 최솟값을 삭제합니다. | 
이중 우선순위 큐가 할 연산 operations가 매개변수로 주어질 때, 모든 연산을 처리한 후 큐가 비어있으면 [0,0] 비어있지 않으면 [최댓값, 최솟값]을 return 하도록 solution 함수를 구현해주세요.
operations의 원소는 큐가 수행할 연산을 나타냅니다.
| operations | return | 
|---|---|
| [I 16,D 1] | [0,0] | 
| [I 7,I 5,I -5,D -1] | [7,5] | 
16을 삽입 후 최댓값을 삭제합니다. 비어있으므로 [0,0]을 반환합니다. 7,5,-5를 삽입 후 최솟값을 삭제합니다. 최대값 7, 최소값 5를 반환합니다.
function solution(operations) {
    const q = []
    for(const v of operations){
        const [command, number] = v.split(' ')
        if (command === 'I'){
            q.push(Number(number))
        } else if (command === 'D'){
            if (q.length !== 0){
                if (number === '1' ){
                    q.sort((a,b) => a-b)
                    q.pop()
                } else {
                    q.sort((a,b) => b-a)
                    q.pop()
                }    
            }
        }
    }
    if (!q.length) return [0,0]
    else {
        const answer = [-2147000000, 2147000000]
        for (const v of q){
            if (v > answer[0]) answer[0] = v
            if (v < answer[1]) answer[1] =v
        }
        return answer
    }
}