백준 10818번 풀이

박수빈·2022년 12월 8일
0

코딩테스트 대비를 위해 매일매일 알고리즘 문제를 풀기로 다짐했다.
1일 1솔은 어려울 수도 있겠지만, 1일 1커밋하듯 적어도 매일 30분씩은 공부하려고 한다.
BFS, DFS 문제를 중심으로 공부하려고, 막연하게 구글에
"코딩 테스트 대비"
라고 쳤더니 어떤 문제부터 풀라는 일종의 백준 로드맵이 나온다.
한 번 따라가보자.

백준 10818번

N개의 정수가 주어진다. 이때, 최솟값과 최댓값을 구하는 프로그램을 작성하시오.

입력
첫째 줄에 정수의 개수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 N개의 정수를 공백으로 구분해서 주어진다. 모든 정수는 -1,000,000보다 크거나 같고, 1,000,000보다 작거나 같은 정수이다.

출력
첫째 줄에 주어진 정수 N개의 최솟값과 최댓값을 공백으로 구분해 출력한다.

첫 번째 코드

N = map(input().split())
a = map([input().split()])
small = a[0]
big = a[0]
cnt = 1

for i in range N:
    if (small<a[i+1]):
        i += 1
    else:
        a[i+1] = small
        i += 1
    cnt += 1
            
for i in range N:
    if (big > a[i+1]):
        i += 1
    else:
        a[i+1] = big
        i += 1
    cnt += 1
    
print(small, big)

바로 compile error가 난다.
일단 map 함수에 대한 이해가 필요할 것 같다.

map()은 파이썬의 내장 함수다.
여러 개의 데이터를 한 번에 다른 데이터로 변환할 때 쓰인다. 주로 한 번에 여러 입력을 받아 결과를 출력하는 코딩 테스트에 많이 쓰일 함수다. list나 tuple을 대상으로 쓰인다고 하는데... 문자열 형태의 데이터를 변환하여 list나 tuple의 요소로 넣는다는 의미로 이해된다.
사용 방식은 다음과 같다.

map(변환 함수, 순회 가능한 데이터)

그러니까

map(어떤식으로 변환할건지, 무슨 데이터를)

이러한 의미로 해석된다. //문법이 영어식이구나!
변환함수 부분에 함수를 정의하여 넣을 수 있는 편리한 함수다.

백준 문제 중 정수 n을 이진수로 변환한 후 1의 위치를 찾는 문제에서
T, n = map(int, input().split()) 과 같은 함수가 정답 코드에 있었다. T는 테스트 케이스, n은 양의 정수였는데, 당시 이 정답 코드를 봤을 때 두 가지 의문이 들었다.

1) 숫자가 입력되는데 int 변환이 꼭 필요한가?
2) T와 n을 어떻게 구분해서 입력받는 거지?

먼저 1번 물음은, input()으로 입력되는 내용은 문자열이기 때문에 변환이 필요하다는 게 지금은 보인다. 당연한 걸 자꾸 잊어버린다. 그러면
map(int(input()).split())
과 같이 함수를 사용하면 변환이 필요가 없을까? 어떤 쪽이 더 효율적인지 궁금하다. 이런 효율에 관련된 Test Case는 어떻게 작성할까?

아무튼, 다시 돌아와서.

두 번째 코드

cnt = int(input())
a = list(map(int, input().split()))
small = a[0]
big = a[0]

for i in range a[1:]:
    if (small > a[i]):
        small = i
    elif (big < a[i]):
        big = i
    
print(small, big)

첫째 둘째 줄로 답이 구분된다는 걸 보고 아, 그러면 첫째 줄은 input()으로 받으면 되겠구나. 생각이 들며 조금 명확해졌다.
둘째 줄에 주어지는 N개의 정수는 공백으로 구분되니 input().split()을 int형으로 받아서 list a에 넣었다. 다른 정답 코드를 보니 변수명을 max, min으로 했던데 small big이라니 개발 안 해 본 티 내는 기분이라 좀 민망하다.
이 코드 역시 compile error가 났는데, 이건 여섯째 줄

for i in range a[1:]

때문이었다.
아니 대체 코드를 왜 이렇게 쓴 거람. range 이후에는 범위를 나타내는 괄호가 등장했어야 하는데, 냅다 리스트 요소를 쭉 내미니 당연히 syntax error가 뜬다.

세 번째 코드, 정답

cnt = int(input())
a = list(map(int, input().split()))
small = a[0]
big = a[0]

for i in a[1:]:
    if (small > i):
        small = i
    elif (big < i):
        big = i
    
print(small, big)

한참만에 채점이 돌아가고 정답이 나왔다!
i를 list a의 요소로 생각하고 하나씩 꺼내서 하나씩 비교한다.
더 작으면 small, 더 크면 big.
아니면 말고.
나는 이 >아니면 말고<부분까지 구현한다고 항상 코드를 지저분하게 쓰는데, 코테 문제에서는 이렇게 아무래도 좋은 예외 부분은 구현하지 않아도 되는 건가? 하는 생각도 들었다.

좀 더 간결한 코드가 있을 것 같아 다른 정답 코드도 살펴보았다.

파이썬 내장함수 min(), max()

min( ) #인수로 받은 자료형 내에서 최소값 반환
max( ) #인수로 받은 자료형 내에서 최대값 반환

파이썬에는 min(), max()라는 내장함수가 있다. //지금 알았다!
이렇게 되면 굳이 for문을 이용해서 자료형 내의 요소들을 비교할 필요가 없다.

min(), max()를 활용한 정답 코드

cnt = int(input()) #첫째줄의 정수 개수 N
numbers = list(map(int, input().split())) #정수를 리스트 요소로 입력
print(min(numbers),max(numbers)) #최소값, 최대값 출력

왠지 마지막 줄은 자꾸 min(numbers[])처럼 써야 할 것 같다.
이게 JAVA 문법이던가?
이렇게 작성하니 코드 길이도 훨씬 짧아지고, 시간도 줄어들었다.
다만 메모리는 고작 8KB 차이인데, 이건 리스트 자료형을 쓰니까 당연한 건가?
아직 모든 궁금증을 해결하지는 못하는 수준이지만, 그래도 꼼꼼하게 한 문제 풀고 나니 조금 마음이 좋다.

profile
무럭무럭 개발자

0개의 댓글