개발팀 내에서 이벤트 개발을 담당하고 있는 무지는 최근 진행된 카카오이모티콘 이벤트에 비정상적인 방법으로 당첨을 시도한 응모자들을 발견하였습니다. 이런 응모자들을 따로 모아 불량 사용자
라는 이름으로 목록을 만들어서 당첨 처리 시 제외하도록 이벤트 당첨자 담당자인 프로도 에게 전달하려고 합니다. 이 때 개인정보 보호을 위해 사용자 아이디 중 일부 문자를 ’’ 문자로 가려서 전달했습니다. 가리고자 하는 문자 하나에 ’’ 문자 하나를 사용하였고 아이디 당 최소 하나 이상의 ’*’ 문자를 사용하였습니다.
무지와 프로도는 불량 사용자 목록에 매핑된 응모자 아이디를 제재 아이디
라고 부르기로 하였습니다.
예를 들어, 이벤트에 응모한 전체 사용자 아이디 목록이 다음과 같다면
응모자 아이디 |
---|
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
}
}