[백준] 10828번 : 스택

솔방울·2023년 6월 12일
0

코딩테스트

목록 보기
10/13
post-thumbnail

문제

정수를 저장하는 스택을 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.

명령은 총 다섯 가지이다.

push X: 정수 X를 스택에 넣는 연산이다.
pop: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.
size: 스택에 들어있는 정수의 개수를 출력한다.
empty: 스택이 비어있으면 1, 아니면 0을 출력한다.
top: 스택의 가장 위에 있는 정수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.

입력

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.

출력

출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.

첫 시도

const fs = require("fs");
let [count,...rest] = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

class Stack {
	constructor(array=[]) {
		this.array = array;
	}
	
	push(x) {
		this.array.push(x);
	}
	
	pop() {
		if (this.array.length > 0) {
            console.log(this.array.pop());
		} else {
            console.log(-1);
        }
	}
	
	size() {
		console.log(this.array.length);
	}
	
	empty() {
		console.log(this.array.length === 0 ? 1 : 0)
	}
  
    top() {
  	    console.log(this.array.length === 0 ? -1 : this.array[this.array.length -1]);
  }
}

const stack = new Stack()

rest.forEach((x) => {
    const method = x.split(" ")[0];
    switch(method) {
        case "push" :
            const num = x.split(" ")[1];
            stack.push(parseInt(num));
            break
        case "pop" :
            stack.pop();
            break
        case "size" :
            stack.size();
            break
        case "empty" : 
            stack.empty();
            break
        case "top" :
            stack.top();
            break
    }
})

class를 이용해 객체를 만들어 풀어보기로 결심했다. 물론 하지만 시간 초과가 뜨는 것이다...!

왜 그럴까 하니 node.js 환경에서 console.log() 를 호출하는 것이 매우 느리다고 한다. 이를 해결하는 방법은 정답을 하나씩 모아서 문자열로 만들어 한번 출력하는 것이다.

두번째 시도

const fs = require("fs");
let [count,...rest] = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

class Stack {
	constructor(array=[], result=[]) {
		this.array = array;
        this.result = result;
	}
	
	push(x) {
		this.array.push(x);
	}
	
	pop() {
		if (this.array.length > 0) {
            this.result.push(this.array.pop());
		} else {
            this.result.push(-1);
        }
	}
	
	size() {
		this.result.push(this.array.length);
	}
	
	empty() {
		this.result.push(this.array.length === 0 ? 1 : 0)
	}
  
    top() {
  	    this.result.push(this.array.length === 0 ? -1 : this.array[this.array.length -1]);
  }
}

const stack = new Stack()

rest.forEach((x) => {
    const method = x.split(" ")[0];
    switch(method) {
        case "push" :
            const num = x.split(" ")[1];
            stack.push(parseInt(num));
            break
        case "pop" :
            stack.pop();
            break
        case "size" :
            stack.size();
            break
        case "empty" : 
            stack.empty();
            break
        case "top" :
            stack.top();
            break
    }
})

console.log(stack.result.join("\n"));

그 결과 개떡같은 코드가 만들어졌다..객체에 result라는 변수도 추가하여 마지막에 줄바꿈 코드와 함께 join() 메서드를 사용하여 문자열로 출력하였다. 물론 이렇게 하는게 OOP나 유지보수 측면에서는 좋으나 코딩테스트에서는 메모리랑 시간 잡아먹게 하는 것 같다...

리팩토링 버전

const fs = require("fs");
let [count,...rest] = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const stack = [];
const result = [];
const implementMethod = {
    push : (x) => stack.push(x),
    pop : () =>  stack.length === 0 ? result.push(-1) : result.push(stack.pop()),
    size : () => result.push(stack.length),
    empty : () => stack.length === 0 ? result.push(1) : result.push(0),
    top : () => stack.length === 0 ? result.push(-1) : result.push(stack[stack.length -1])
}

rest.forEach((x) => {
    const [method,num] = x.split(" ");
    implementMethod[method](num);
})

console.log(result.join("\n"));

switch 문을 쓰지 말아야 한다는 것에 대한 아티클을 보고 action object라는 형식으로 리팩토링 해보았다. push 하나 때문에 인수를 계속 넘겨줘야 하는 점이 걸리지만, 확실히 깔끔하다. result라는 변수를 만든 이유는 위에서도 얘기했지만 console.log()를 쓰지 않기 위함이다.

회고

  • 백준 환경에서 console.log()를 자주 출력하기보다는 답을 한꺼번에 모아 개행 문자인 \n을 사용하여 한번 출력하는 것이 좋다.

  • if/else 구문이 길어지는 것이 보기 싫어 swtich문을 이용했는데, case일 때로 바로 이동되는 것이 아니라 이것도 결국 위에서 아래로 내려가는 절차적 코딩이다. 또한 break 을 선언해야 하는 불편함이 있다. 이에 design pattern 중 action obejct라는 방법이 있다. action을 객체로 관리하는 것이다.

profile
당신이 본 큰 소나무도 원래 작은 솔방울에 불과했다.

0개의 댓글