컴퓨터 공부/📚 Baekjoon(백준)

[백준/알고리즘/python/java] 10828번 - 스택

letzgorats 2021. 2. 13. 12:29

이미지를 누르면 문제링크를 보실 수 있습니다.
이미지를 누르면 문제링크를 보실 수 있습니다.
[10828번 - 스택]

파이썬에서 스택 자료구조 라이브러리를 따로 제공하지 않는다.

대신, 리스트를 스택으로 기능하도록 구현할 수 있다.

이 문제가 바로 그런 문제이다.

문제에서 주어진 다섯가지 명령을 함수로 만들어도 되는데, 우선 스택을 Class 로 만들어봤다.

 

(코드는 아래와 같다.-python)

import sys
input = sys.stdin.readline
class Stack:
    def __init__(self):
        self.stack = []

    def __len__(self):              # 스택의 길이(크기)
        return len(self.stack)

    def push(self, item):			# 스택에 item 집어넣기
        self.stack.append(item)

    def pop(self):					# 스택의 가장 위에 있는 원소 빼내기
        if not self.empty():
            return self.stack.pop(-1)
        else:
            return -1
            exit()

    def clear(self):				# 스택 비우기
        slef.stack = []

    def empty(self):				# 스택이 비어있는지 비어있지 않은지 
        return len(self.stack) == 0

    def size(self):					# 스택의 크기(길이)
        return len(self.stack)

    def top(self):					# 스택의 top 리턴
        if not self.empty():
            return self.stack[-1]
        else:
            return -1
            exit()


if __name__=="__main__":

    s = Stack()
    n = int(input())
    for i in range(n):
        command = input()
        if 'push' in command:
            cmd = command.strip().split()[1]
            s.push(cmd)
        elif 'pop' in command:
            print(s.pop())
        elif 'size' in command:
            print(s.size())
        elif 'empty' in command:
            print(int(s.empty()))
        elif 'top' in command:
            print(s.top())

다섯가지 명령 외에도 stack에서 활용할 만한 함수를 만들어봤다. 

처음에는

「import sys

  input = sys.stdin.readLine」 를 안 넣어줘서 시간초과가 났다.

대부분의 시간초과 문제는 input() 을 sys.stdin.readLine() 으로 바꿔주니까 해결이 되곤 했는데,

이 참에 둘의 차이점에 대해 알아보자.

 

더보기

출처 : velog.io/@gouz7514/%ED%8C%8C%EC%9D%B4%EC%8D%AC-input-vs-sys.stdin.readline

 

[파이썬] input() vs sys.stdin.readline()

코딩 테스트를 연습하는 분들이라면 문제는 맞았음에도 효율성 때문에 골머리 앓은 경험이 있을 것이다.(올 여름 카카오 인턴 코딩 테스트에서도 효율성을 통과하지 못함ㅠ)평소에는 무분별한

velog.io

 

 input()

: 입력으로부터 한 줄을 읽어들인 뒤, 문자열로 변환 후(개행은 벗겨내고) 반환한다.

  즉, input()은 사용자의 입력을 받고 → 문자열로 변환 → 추가 strip 진행 의 과정을 거치는 것이다.

 

 또한 input()은 사용자로부터 입력을 받기 전 이를 기다리기 위해 prompt를 가지고 있다. 때문에 대량의 입력을 받는 경우라면 입력을 받고 prompt를 띄우고 의 과정을 반복하므로 오류가 발생할 가능성이 존재한다. (여러 자료를 참고해 제 방식대로 설명한 내용이라 정확하지 않을 수 있습니다.)

 

 sys.stdin.readline()

: stdin  standard input을 뜻하며 얼핏 보면 input() 과 같은 동작을 수행한다고 생각할 수 있다.

sys.stdin.readline()은 사용자의 입력을 받지만 개행 문자도 입력을 받을 수 있다. 또한 입력 크기에 제한을 줌으로써 한번에 읽어들일 문자의 수를 정할 수 있다.

>>> num = sys.stdin.readline(2) # 입력 : 1234
>>> print(num) # 결과 : 12

python documentation - sys
input()과 가장 큰 차이점은 input()  내장 함수로 취급되는 반면 sys 에 속하는 메소드들은 file object로 취급된다.

즉, 사용자의 입력만을 받는 buffer를 하나 만들어 그 buffer에서 읽어들이는 것이다.

input()은 더 이상 입력이 없는데도 수행될 경우 EOFerror를 뱉어내는 반면 sys.stdin.readline()은 빈 문자열을 반환한다. 어떻게 보면 에러에 조금 더 안전할 수 있다.

 

또한, 코드에서

if __name == "__main__": 을 안 써줘도 잘 작동되는데, 이것의 정체가 무엇인지도 알아보자.

그전에, 클래스 객체의 메소드를 호출하는 방법을 한번 살펴보자.

 

더보기

파이썬 메서드의 첫 번째 매개변수 이름은 관례적으로 self를 사용한다. 객체를 호출할 때 호출한 객체 자신이 전달되기 때문에 self를 사용한 것이다. 물론 self말고 다른 이름을 사용해도 상관없다.

※ 메서드의 첫 번째 매개변수 self를 명시적으로 구현하는 것은 파이썬만의 독특한 특징이다. 예를 들어 자바 같은 언어는 첫 번째 매개변수 self가 필요없다.

[메서드의 또 다른 호출 방법]

잘 사용하지는 않지만 다음과 같이 클래스를 통해 메서드를 호출하는 것도 가능하다. 아래와 같이 클래스 이름.메서드 형태로 호출할 때는 객체 a를 첫 번째 매개변수 self에 꼭 전달해 주어야 한다.

>>> a = FourCal() >>> FourCal.setdata(a, 4, 2)

 반면에 다음처럼 객체.메서드 형태로 호출할 때는 self를 반드시 생략해서 호출해야 한다.

>>> a = FourCal() >>> a.setdata(4, 2)

다시 본론으로 돌아와서, if __name == "__main__": 을 쓰는 이유가 무엇일까?

모듈을 실행할 수 있는 방법은 직접 실행하거나 임포트하거나.

둘 중 하나이다. 

더보기

파이썬은 인터프리터 명령어로 실행되면 다른 언어들과는 다르게,자동으로 실행되는 메인함수가 없다.

파이썬은 메인 함수가 없는 대신 들여쓰기 하지 않는 모든 코드(level 0코드)를 실행한다.

다만, 함수나 클래스는 정의되었지만, 실행되지는 않는다.

 

main.py와 sub.py를 만들어 테스트해보자.

# sub.py

print("sub 모듈 시작")
print("sub.py의 __name__ : ", __name__)
print("sub 모듈 끝")

아래의결과를 보면 sub.py 스크립트를 실행했으므로 __name__은 __main__이 된다.

sub 모듈 시작
sub.py의 __name__ :  __main__
sub 모듈 끝

이제 main.py에서 sub를 import해서 실행시켜보자.

# main.py

import sub
print("main.py의 __name__ : ", __name__)

아래의 결과를 보면 sub.py 파일과 main.py 파일의 __name__ 변수 값이 출력된다.

파이썬에서 import로 모듈을 가져오면 해당 스크립트 파일이 한번 실행된다.

따라서 sub 모듈을 가져오면 sub.py 안의 코드가 실행되며 __name__ 변수에는 'sub'가 들어있고,

main.py의 __name__ 변수에는 '__main__'이 들어있다.

sub 모듈 시작
sub.py의 __name__ :  sub
sub 모듈 끝
main.py의 __name__ :  __main__

조금더 자세하게 알아보자

<main.py>

# main.py

def func():
    print("func main.py")

print("main.py 있는 곳")

if __name__ == "__main__":
    print("main.py 직접 실행")
    print("main.py의 __name__ : ", __name__)
else:
    print("main.py가 임포트되어 사용됨")

결과를 보면 main.py를 실행했을때 __name__은 main.py가 될것이다.

그렇다면

if__name__ == "__main__": ◀ 여기 if문에 걸리게 되므로 if문 안에 있는게 실행된다.

else: ◀ 이 부분은 실행이 되지 않는다.

 

<출력 결과>

main.py 있는 곳
main.py 직접 실행
main.py의 __name__ :  __main__

이제 sub.py에서 아래 코드를 실행해보자.

<sub.py>

# sub.py

import main

print("sub.py 있는 곳")

main.func()

if __name__ == "__main__":
    print("sub.py가 직접 실행")
    print("sub.py의 __name__ : ", __name__)
else:
    print("sub.py가 임포트되어 사용됨")

 

출력 결과를 보면 sub.py에서 main.py를 import를 했으므로 main.py가 실행되고

main.py에서 직접 실행이 된 것이 아니라 import가 되어서 실행됐으므로

main.py 에서는 당연히 if문에 안걸리고 else문으로가서 "main.py가 임포트되어 사용됨"이 출력된다.

그리고 차례대로 "sub.py 있는 곳" 이 출력되고 main함수의 func 출력, 그리고 sub.py에서의 if문을 타게 된다. 

 

<출력 결과>

main.py 있는 곳

main.py가 임포트되어 사용됨

sub.py 있는 곳

func main.py

sub.py가 직접 실행

sub.py의 __name__ :  __main__

namespace 에 관련해 더 배워보고 싶다면, 아래 출처의 [땅뚱 창고]를 참고해보면 된다.

출처 : do-hansung.tistory.com/10

출처: https://pinocc.tistory.com/175 [땅뚱 창고]

 

(이전에 자바로 풀었던 코드는 아래와 같다-java)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;

public class Main{
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		StringTokenizer st =null;
		Stack<Integer> stack = new Stack<>();
		for(int i=0;i<n;i++) {
			st = new StringTokenizer(br.readLine()," ");
			switch(st.nextToken()) {
			case "push":
				stack.push(Integer.parseInt(st.nextToken()));
				break;
			case "pop":
				if(stack.isEmpty()) {
					System.out.println("-1");
				}
				else {
					System.out.println(stack.pop());
				}
				break;
			case "size":
				System.out.println(stack.size());
				break;
			case "empty":
				if(stack.isEmpty()) {
					System.out.println("1");
				}
				else {
					System.out.println("0");
				}
				break;
			case "top":
				if(stack.isEmpty()) {
					System.out.println("-1");
				}
				else {
					System.out.println(stack.peek());
				}
				break;
			}
		}
		br.close();
	}
}
반응형