큐는 선입선출(FIFO)의 규칙을 가지는 자료구조이다.
즉, 가장 먼저 넣은 것이 가장 먼저 나오는 구조이다. (일반적으로 매장에서 물건을 팔 때 가장 오래전에 들어온 물건을 먼저 파는 것과 동일하다고 생각하면 된다.)
자바스크립트에서 push, shift 메서드를 사용하면 일반 배열로 큐를 구현할 수 있지만, 시간 복잡도 이슈가 있다.
push는 단순히 배열 마지막에 요소를 추가하기 때문에 O(1)의 시간 복잡도를 가지지만, shift는 맨 앞의 요소를 제거하고 다른 요소들을 하나씩 앞으로 이동해야 하기 때문에 O(n)의 시간 복잡도를 가지게 된다.
따라서 직접 클래스로 구현하는 것이 좋다.
이때 맨 뒤로 값을 추가하고 맨 앞의 값을 반환하므로 맨 앞과 맨 뒤의 위치를 저장하는 변수가 각각 있어야 한다.
값을 저장할 객체(storage), 맨 앞을 가리키는 인덱스(front), 맨 뒤를 가리키는 인덱스(rear)큐 사이즈(size), 데이터 추가(enqueue), 데이터 삭제(dequeue), 그외 비어있는 여부를 나타내는 empty, 맨 앞의 요소를 반환하는 head, 맨 뒤의 요소를 반환하는 back 등의 메서드도 추가할 수 있다.enqueue는 맨 뒤에 값을 추가하고 맨 뒤의 인덱스를 증가하는 방식으로 구현할 수 있고, dequeue는 맨 앞의 값을 제거하여 반환하고 맨 앞의 인덱스를 증가하는 방식으로 구현할 수 있다.
class Queue{
constructor(){
this.storage = {};
this.front = 0;
this.rear = 0;
}
size(){
return this.rear - this.front;
}
enqueue(val){
this.storage[this.rear] = val;
this.rear++
}
dequeue(){
if(this.size() === 0){
return undefined
}
const val = this.storage[this.front];
delete this.storage[this.front];
this.front++;
if(this.front === this.rear){
this.front = 0;
this.rear = 0;
}
return val;
}
}
const queue = new Queue()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
console.log(queue.dequeue())
console.log(queue.dequeue())
console.log(queue.dequeue())
console.log(queue.size())
문제에서 주어진 조건대로 아래 6가지 연산을 구현한다.
주의 : 프로퍼티 이름이 메서드 이름과 겹치면 덮어씌워지기 때문에 프로퍼티 이름을 this.front 대신 this.head로 사용해주었다.
const fs = require('fs');
const input = fs.readFileSync(process.platform === 'linux' ? '/dev/stdin' : './test.txt').toString().trim().split('\n');
const N = +input.shift();
const answer = [];
class Queue{
constructor(){
this.storage = {};
this.head = 0;
this.rear = 0;
}
size(){
return this.rear - this.head;
}
empty(){
return Number(this.size() === 0);
}
push(val){
this.storage[this.rear] = val;
this.rear++;
}
pop(){
if(this.empty()) return -1;
const removed = this.storage[this.head];
delete this.storage[this.head];
this.head++;
if(this.head === this.rear){
this.head = 0;
this.rear = 0;
}
return removed;
}
front(){
if(this.empty()) return -1;
return this.storage[this.head];
}
back(){
if(this.empty()) return -1;
return this.storage[this.rear - 1];
}
}
const queue = new Queue();
for(let i=0;i<N;i++){
const command = input[i];
if(command === "pop"){
answer.push(queue.pop())
}else if(command === "size"){
answer.push(queue.size())
}else if(command === "empty"){
answer.push(queue.empty())
}else if(command === "front"){
answer.push(queue.front())
}else if(command === "back"){
answer.push(queue.back())
}else{
const [c, n] = command.split(' ');
if(c === "push") queue.push(Number(n));
}
}
console.log(answer.join('\n'));
처음에 큐로 어떻게 풀어야 할 지 아이디어를 얻지 못 하다가 힌트를 찾아보고 dequeue, enqueue를 반복하면 원형처럼 풀 수 있다는 것을 알게되었다.
(K - 1 번 만큼 꺼내서 뒤에 다시 넣으면 원형으로 돌리는 것과 같음.)
그런데 dequeue, enqueue가 최대 N*K 만큼 발생하여 메모리 초과가 발생했다.
const fs = require('fs');
const input = fs.readFileSync(process.platform === 'linux' ? '/dev/stdin' : './test.txt').toString().trim().split('\n');
const [N, K] = input[0].split(' ').map(Number);
const answer = [];
class Queue{
constructor(){
this.storage = {};
this.front = 0;
this.rear = 0;
}
size(){
return this.rear - this.front;
}
enqueue(val){
this.storage[this.rear] = val;
this.rear++
}
dequeue(){
if(this.size() === 0) return undefined;
const val = this.storage[this.front];
delete this.storage[this.front];
this.front++;
if(this.front === this.rear){
this.front = 0;
this.rear = 0;
}
return val;
}
}
const queue = new Queue();
for(let i=1;i<=N;i++){
queue.enqueue(i);
}
for(let i=0;i<N;i++){
for(let j=1;j<K;j++){
const val = queue.dequeue()
queue.enqueue(val)
}
answer.push(queue.dequeue())
}
console.log('<' + answer.join(', ') + '>');
다른 방식으로 인덱스를 규칙을 이용해 구하는 방식으로 풀었더니 성공했다.
splice도 시간복잡도 면에서 좋지는 않지만 입력 범위가 최대 5000이라 O(n)은 범위 안에 들어서 가능했다.
const fs = require('fs');
const input = fs.readFileSync(process.platform === 'linux' ? '/dev/stdin' : './test.txt').toString().trim().split('\n');
const [N, K] = input[0].split(' ').map(Number);
const answer = [];
const queue = Array.from({length:N}, (_,i) => i+1);
let idx = 0;
for(let i=0;i<N;i++){
idx = (idx - 1 + K) % queue.length
answer.push(queue[idx])
queue.splice(idx,1)
}
console.log('<' + answer.join(', ') + '>');
const fs = require('fs');
const input = fs.readFileSync(process.platform === 'linux' ? '/dev/stdin' : './test.txt').toString().trim().split('\n');
let idx = 0;
const N = +input[idx++];
const board = Array.from({length: N}, () => Array(N).fill(0));
const K = Number(input[idx++]);
for(let i=0;i<K;i++){
const [x,y] = input[idx++].split(' ').map(Number)
board[x-1][y-1] = 2;
}
const L = Number(input[idx++]);
const turns = {};
for (let i = 0; i < L; i++) {
const [t, d] = input[idx++].split(' ');
turns[Number(t)] = d;
}
class Queue{
constructor(){
this.storage = {};
this.front = 0;
this.rear = 0;
}
size(){
return this.rear - this.front
}
enqueue(val){
this.storage[this.rear] = val;
this.rear++;
}
dequeue(){
if(this.size() === 0) return undefined;
const val = this.storage[this.front];
delete this.storage[this.front];
this.front++;
return val;
}
head(){
return this.storage[this.front]
}
back(){
return this.storage[this.rear - 1]
}
}
const snake = new Queue();
let time = 0;
let dir = 0;
const direction = [[0,1],[1,0],[0,-1],[-1,0]];
snake.enqueue([0,0])
board[0][0] = 1
while(true){
const [x, y] = snake.back();
const [dx, dy] = direction[dir];
const nx = x+dx;
const ny = y+dy;
time++
if(nx < 0 || nx >= N || ny < 0 || ny >= N) break;
if(board[nx][ny] === 1) break;
const isApple = board[nx][ny] === 2;
snake.enqueue([nx,ny])
board[nx][ny] = 1;
if(!isApple){
const [tx,ty] = snake.dequeue();
board[tx][ty] = 0;
}
if(turns[time]){
if(turns[time] === "D") dir = (dir+1)%4
else dir = (dir+3)%4
}
}
console.log(time);
const fs = require('fs');
const input = fs.readFileSync(process.platform === 'linux' ? '/dev/stdin' : './test.txt').toString().trim().split('\n');
const [N,K] = input.shift().split(' ').map(Number);
const count = Array(21).fill(0)
let answer = 0;
class Queue{
constructor(){
this.storage = {};
this.front = 0;
this.rear = 0;
}
size(){
return this.rear - this.front
}
enqueue(val){
this.storage[this.rear] = val;
this.rear++
}
dequeue(){
if(this.size() === 0) return undefined;
const val = this.storage[this.front];
delete this.storage[this.front];
this.front++;
return val
}
head(){
return this.storage[this.front]
}
}
const queue = new Queue();
for(let i=0;i<N;i++){
const len = input[i].length
answer += count[len]
queue.enqueue(len)
count[len]++
if(queue.size() > K){
const old = queue.dequeue()
count[old]--
}
}
console.log(answer);