종우의 삶 (전체 공개)

1 - 백준, 인풋 그리고 나 본문

일지/코딩 테스트 , Algorithm

1 - 백준, 인풋 그리고 나

jonggae 2024. 5. 27. 16:02

다양한 코딩테스트 플랫폼이 있다.

 

아마 대부분의 사람들이 프로그래머스나 백준 사이트를 이용하여 코딩테스트를 시작하고, 준비할 것이다.

나도 처음 파이썬을 시작하였을 때 백준에서 쉬운 문제들을 하나씩 풀어보곤 했는데,

이후 프로그래머스에 익숙해지다보니, 각 플랫폼마다 문제를 푸는 형식이 달라서 헷갈리곤 했다.

 

우선 파이썬은 쉽다. 확실히 쉬웠다.

자바를 사용하여 몸을비틀며 코드를 쓰는 것 보다는 굉장히 직관적이고 편한 기분이다.

아무것도 몰랐을 때에는, 그냥 몰랐을 것이지만 자바를 배우고 다시 파이썬으로 돌아오니 얼마나 편한지 알 수 있었다.

 

어쨌든, 백준 티어를 올리기 위해 쉬운 문제부터 풀어보며 하나씩 익숙해지는 중이다.


 

백준은 시간, 메모리 제한도 전부 자세히 나와있으며

문제, 입 / 출력이 깔끔한 형태로 제시되어있다.

 

답안은 보통 입력된 데이터를 이용하여 옳은 출력을 내면 된다. 다른 코딩테스트 플랫폼도 마찬가지겠지.

하지만 이런 시작도 초보자에겐 쉽지가 않다.

 

문제를 읽고 아하 이렇게 풀면 되겠네~ 하며

대뜸 제출 버튼을 누르면 언어와 소스 코드를 작성할 창이 떡하니 뜬다. 당연히 IDE처럼 자동완성은 되지 않으며, 모든것을 스스로 작성해야한다. IntelliJ 에서 Java코드를 작성할때와는 기분이 무척이나 다르다.

 

main, sout, fori등 묵묵부답인 상황이 많다.

그래서 코딩 테스트 연습을 할 때에는 IDE에서 작성하고, 다시 옮겨서 제출하거나 하는 방법도 사용하는 듯 하다. 나도 지금 그러고 있고.

텅 비어있다. 마치 나의 내일 처럼.

 

뭐 어쨌든 여기저기 찾아보면 '입력'값을 받아서 코드를 작성하는 방법을 알 수 있다. 사실 백준 도움말에 가보면 예제 코드를 확인할 수 있다.

 

그렇다면 지금부터 본론이다.

저 1번 라인의 map(), input().split()에 대해 적어보도록 한다.

 

백준 사이트의 문제 방식을 로컬환경에서 구현해보고 싶다면, 이렇게 작성하면 된다.

 

예를들어 PyCharm에서 이렇게 작성하는 것이다.

import sys
from io import StringIO

# 입력 예시를 실제로 적는다
example_input = """ 14 30 """

# sys.stdin을 StringIO 객체로 대체하여 입력을 시뮬레이션한다.
sys.stdin = StringIO(exaple_input)

# 이 아래로 실제 코드를 진행한다.

 

100% 정확한 매커니즘은  잘 모르겠다. 그렇다. 잘 모르겠다. 

 

찾아보니 sys.stdin 은 사용자가 터미널이나 콘솔에서 입력하는 데이터를 읽을 때 사용하고

이것을 StringIO 로 문자열을 파일 처럼 다룰수 있게 변경하여 객체처럼 사용할 수 있다는 것이었다.

어쨌든 데이터를 입력받아 이리저리 사용할 수 있다는 뜻인가보다.

 

따옴표 3개를 연달아 쓴 """ """ 내부에 공백으로 데이터들을 분리하여 작성한다.  -> """ 를 쓴 것은 여러 줄의 데이터를 입력할 경우도 있기 때문에 고려하여 기본으로 사용했다.

 

자 이제 백준의 텅 비어있는 제출 소스코드에 이렇게 적어보자

A, B = map(int, input().split())
print(A+B)

 

위에서 나타난 예제 소스코드와 동일하다. 

1000번 문제를 예시로 들었다면, 맞았습니다! 가 나타날것이다.

 

이것이 백준 코딩테스트 시작의 기본이었다. 문제에서 주어진 입력값을 가져오고 변수로 저장하는 방법.

그 변수가 있어야 뭘 하든지 할 것아닌가?

 

자바에서는 클래스를 선언하고, 스캐너객체를 사용하고 별 쌩쇼를 해야하는데 우선 파이썬이 이리 간단하게 작성되는 것에 놀라웠다. 

 

A, B = map(int, input().split())

 

만약 입력이 """14 30"""" 이었다면, 14와 30을 공백 한칸으로 입력한 것이 된다.

 

input() 함수는 이 값을 A, B에 저장하려고 하는데, 이때 .split() 함수로 공백 한칸별로 나누어 리스트로 변환하게 된다.

 

그렇다 리스트이다. 여러 입력값을 단순히 input(). split() 사용하면 리스트 형태인 [14, 30]으로 저장이 될 것이다.

 

이때 map()으로 int, 즉 정수 값으로 자료형을 확정지어주고, 결국엔 int의 리스트 [14, 30]이 생성되는 것이다.

 

여기서 java를 사용하던 나에게  A, B = 와같은 변수 선언은 충격적이었다.

 

변수 할당을 그 즉시 A와 B에 할 수 있는 것이었다.

 

결과적으로 저 한줄은 입력값 2개를 A와 B에 차례로 저장하겠다는 뜻이된다. 

 

 

입력값이 여러줄이면 어떻게 할까?

import sys
from io import StringIO

example_input = """3
14 30
20 50
10 20"""

sys.stdin = StringIO(example_input)

 

비슷하게 시작한다. 이번에 입력값은 '앞으로 몇개의 입력 값이 나올거다' 라고 선언하는 3과 

그에 따르는 3줄의 입력값이다.

 

우선 궁금한 나는 이런 것을 작성해본다.

 

A = input()
print(A)
A = input()
print(A)
A = input()
print(A)
A = input()
print(A)

 

라인별로 A에 어떤 입력값을 저장하고 출력해봤다.

 

결과는

example_input = """3
14 30
20 50
10 20""" 에서 입력했던 그대로

 

3

14 30

20 50

12 20 이 출력된다.

 

input함수의 호출마다 한 줄씩 데이터를 읽는 것이라고 할 수 있겠다.

그렇다면 이것을 반복문으로 만들어 사용할수도 있겠는데, 라는 생각을 떠올려야한다.

 

for _ in range(4):
    A = input()
    print(A)

 

for 문에서  _  는 반복문에서 사용되지 않는 변수를 나타낸다.

이 for문은 다른 형태로 계속 변형이 가능한데,

for line in sys.stdin:
    A = line.strip()
    print(A)

이 for문을 사용하면 입력한 모든 값들이 출력된다. 

 

이러한 모든 요소를 사용하면 이러한 코드를 해석 할 수 있다.

import sys
from io import StringIO

example_input = """3
14 30
20 50
10 20"""

sys.stdin = StringIO(example_input)

n = int(sys.stdin.readline().strip())

for _ in range(n):
    line = sys.stdin.readline().strip()
    numbers = list(map(int, line.split()))
    print(sum(numbers))

 

먼저 변수 n을 지정한다.

이 변수 n에는 입력된 값들의 첫 줄을 int로 저장할 것이다. sys.stdin.readline()으로 읽어오면 3 뒤에 붙은 \n같은 줄바꿈 문자도 포함되어있다. 공백보다는 우리는 값이 중요하므로 strip() 사용해 문자열 앞 뒤의 공백과 줄바꿈을 없애준다.

그리고 int로 저장한다.

-> 결과 : n 에는 int인  3이 저장

 

이후 나머지 입력 숫자들을 가지고 두 수의 합을 출력해내는 과정이다.

 

앞으로 n개의 항목이 나온다고 명시했으므로, 3개의 출력사항이 생성될 것이다.

 

for _ in range(n):

range()는 n-1까지의 숫자를 생성한다. 0부터 시작이므로 어쨌든 3개인 셈이다.

 

line = sys.stdin.readline().strip()

그런 다음 숫자 값 2개를 line이라는 변수로 저장하고 strip으로 줄바꿈 문자를 없애준다.

결국 line = "14 30" 문자열이 되는 것이다.

 

하지만 문자열을 가지고서는 수리적인 계산을 진행할 수 없다.

numbers = list(map(int, line.split()))

그래서 numbers 라는 리스트를 만드는 것이다. "14 30" 이라는 문자열이 split()을 거치면

["14", "30"]인 문자열로 이루어진 리스트가 된다.

이것을 map 함수로 정수형으로 바꾸어 저장하게되면 결과적으로 정수로 이루어진 리스트

numbers = [14, 30]이 되는것이다.

 

print(sum(numbers))

 

그리고 그 정수 리스트의 값을 다 더해준다. 짠. 끝.

 


결론

글을 쓰다가 이해가 많이 되었다. 백준 문제에서는 다양한 형태의 입력 방식이 있고, 이 입력들을 어떻게 바꾸고 변환하여 원하는 로직 속으로 넣을 수 있는지 알게되었다.

 

한줄짜리 입력은 어떻게 대충 이해가 되었으나, 여러줄을 입력받고 조작하는 것은 직관적으로 알 수가 없었다. 애초에 파이썬의 문법을 정확히 전부 알지못하니 그런 점이 힘들었던 것이다.

 

하지만 이렇게 글을 작성하면서, 입력값을 어떻게 정리하고 사용할 수 있는지 익힐 수 있었다. 

 

이제 더 문제를 풀어보자. 가장 기본적인 데이터 입력을 배웠으니, 이제 이 입력값으로 무엇을 만들어 볼 수 있을까? 

Comments