[이것이 코딩 테스트다 with 파이썬] Part 04. 부록 - APPENDIX A 코딩 테스트를 위한 파이썬 문법(1)

박미진·2022년 7월 24일
0

코딩 테스트

목록 보기
1/9
  • 파이썬은 문법이 매우 간결하면서도 다루기 쉬운 언어로 알고리즘을 구현할 때도 다른 언어에 비해서 코드가 짧은 편

01. 자료형

  • 모든 프로그래밍은 결국 데이터를 다루는 행위인만큼 자료형에 대한 이해는 프로그래밍의 길에 있어서의 첫걸음이라 할 수 있음
  • 파이썬의 자료형은 다른 언어에서 사용되는 기본 자료형을 제공할 뿐만 아니라 사전자료형, 집합자료형 등 강력한 기능을 제공하는 자요형을 기본으로 내장하고 있어 매우 편리

✎ 대부분의 언어에서는 HashMap과 같은 별도의 라이브러리를 이용해야 파이썬의 사전자료형기능을 구현할 수 있음
✎ 파이썬에서는 기본 자료형이 이를 지원하므로 구현이 편리하다는 장점

1. 수 자료형(number)

  • 코딩테스트에서 가장 기본적인 자료형
  • 데이터는 모든 수(number)로 표현할 수 있음
  • 대부분의 프로그램에서는 일반적으로 정수와 실수가 많이 사용, 그 중에서도 정수를 기본으로 사용

(1) 정수형(integer)

  • 정수를 다루는 자료형
  • 양의 정수, 음의 정수, 0
  • 코딩테스트에서 출제되는 알고리즘 문제 대부분 입력과 출력 데이터가 정수형
<입력>
# 양의 정수
a = 10 
print(a)

# 음의 정수
a = -2 
print(a)

# 0
a = 0 
print(a)

<출력>
10
-2
0

(2) 실수형

  • 소수점 아래의 데이터를 포함하는 수 자료형
  • 변수에 소수점을 붙인 수를 대입하면 실수형 변수로 처리
  • 소수부가 0이거나 정수부가 0인 소수는 0을 생략하고 작성할수 있음

☑ 정수부 : 소수점 이하의 수를 뺀 정수 부분
☑ 소수부 : 소수점 오른쪽에 놓인 수의 부분

<입력>
# 양의 실수
a = 156.23
print(a)

# 음의 실수
a = -10.53
print(a)

# 소수부가 0일 때 0 생략
a = 2.
print(a)

# 정수부가 0일 때 0 생략
a = -.2
print(a)

<출력>
156.23
-10.53
2.0
-0.2
  • e나 E를 이용한 지수표현방식 : e 다음에 오는 수는 10의 지수부를 의미
    예) 1e9 => 10의 9제곱(1,000,000,000)
    ☑ 유효 숫자e(지수) = 유효숫자 * 10(지수)
  • 지수표현방식은 코딩테스트에서 많이 사용됨
    예) 최단 경로 문제에서는 도달할 수 없는 노드에 대하여 최단 거리를 "무한(INF)"으로 설정하곤 함
  • 큰 수를 표현할 때, 0의 개수가 많아지면 자릿수가 헷갈리는 경우가 많기 때문에 10억을 코드에 입력하는 것보다 1e9로 표현하는 것이 더 실수할 확률이 적다는 장점
<입력>
# 10억의 지수 표현 방식
a = 1e9
print(a)

# 752.5
a = 75.25e1
print(a)

# 3.594
a = 3594e-3
print(a)

<출력>
1000000000.0
752.5
3.954
  • 보통 컴퓨터 시스템은 수 데이터를 처리할 때 2진수를 이용, 실수를 처리할 때 부동소수점 방식을 이용
  • IEEE754 표준에서는 실수형을 저장하기 위해 4바이트, 혹은 8바이트로 고정된 크기의 메모리를 할당하며, 이러한 이유로 인해 현대 컴퓨터 시스템은 대체로 실수 정보를 표현하는 정확도에 한계를 가짐

✓ 컴퓨터가 실수를 정확히 표현하지 못한다는 사실 기억!!

<입력>
a = 0.3 + 0.6
print(a)

if a == 0.9:
	print(True)
else:
	print(False)
    
<출력>
0.8999999999999999
False

→ 소수점 값을 비교하는 작업이 필요한 문제라면 실수 값을 비교하지 못해서 원하는 결과를 얻지 못할수 있음
=> round()함수 이용
☑ round()함수

  • 호출할 때 인자를 넣음
    - 첫번째 인자 : 실수형데이터
    - 두번째 인자 : 반올림하고자하는 위치-1
    → 두번째 인자 없이 인자를 하나만 넣을 때는 소수점 첫째자리에서 반올림
  • 흔히 코딩테스트 문제에서는 실수형 데이터를 비교할 때 소수점 다섯번째 자리에서 반올림한 결과가 같으면 정답으로 인정하는 식으로 처리
<입력>
a = 0.3 + 0.6
print(round(a, 4))

if round(a, 4) == 0.9:
	print(True)
else:
	print(False)
    
<출력>
0.9
True

(3) 수 자료형의 연산

  • 사칙연산(+, -, *, /)을 이용해 계산
    ★ 나누기 연산자 주의해서 사용
  • 나누기 연산자(/)는 나눠진 결과를 기본적으로 실수형으로 처리
  • 나머지 연산자(%)
    예) 특정한 변수 a가 홀수인지 알아볼 때 'a를 2로 나눈 나머지가 1인지'확인
  • 몫 연산자(//) : 나눈 결과에서 몫만을 얻고자 할 때
a = 7
b = 3
<입력>
# 나누기
print(a / b)

# 나머지
print(a % b)

# 몫
print(a // b)

<출력>
2.3333333333333335
1
2
  • 거듭제곱연산자(**) : x ** y 형식으로 이용
<입력>
a = 5
b = 3
print(a ** b)

<출력>
125

2. 리스트 자료형

  • 여러 개의 데이터를 연속적으로 담아 처리하기 위해 사용할 수 있음
  • 내부적으로 배열(array)을 채택하고 있으며 연결 리스트 자료구조 기능을 포함하고 있어 append(), remove() 등의 메서드를 지원

(1) 리스트 만들기

  • 대괄호([ ])안에 원소를 넣어 초기화
  • 쉼표(,)로 원소를 구분
  • 리스트의 원소에 접근할 때는 인덱스(index)값을 괄호 안에 넣음
  • 인덱스는 0부터 시작
  • 비어있는 리스트를 선언하고자 할 때 : list() 혹은 간단히 대괄호([ ])를 이용할 수 있음
예) 1부터 9까지의 정수 데이터를 담는 리스트 만든 뒤, 특정한 인덱스의 원소에 접근하여 출력
<입력>
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(a)

# 인덱스 4, 즉 다섯번째 원소에 접근
print(a[4])

# 빈 리스트 선언 방법 1
a = list()
print(a)

# 빈 리스트 선언 방법 2
a = []
print(a)

<출력>
[1, 2, 3, 4, 5, 6, 7, 8, 9]
5
[]
[]
# 크기가 N이고, 모든 값이 0인 1차원 리스트 초기화
<입력>
n = 10
a = [0] * n
print(a)

<출력>
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

(2) 리스트의 인덱싱과 슬라이싱

  • 인덱싱(indexing) : 인덱스 값을 입력하여 리스트의 특정한 원소에 접근하는 것
    → 양의 정수와 음의 정수 모두 사용할 수 있음
    → 음의 정수를 넣으면 원소를 거꾸로 탐색
  • 인덱싱을 하여 특정원소에 접근한 뒤 그 값을 간단히 바꿀 수 있음
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
<입력>
# 뒤에서 첫번째 원소 출력
print(a[-1])

# 뒤에서 세번째 원소 출력
print(a[-3])

# 네번째 원소값 변경
a[3] = 7
print(a)

<출력>
9
7
[1, 2, 3, 7, 5, 6, 7, 8, 9]
  • 슬라이싱(slicing) : 리스트에서 연속적인 위치를 갖는 원소들을 가져와야 할 때
    → 대괄호 안에 콜론(:)을 넣어서 시작 인덱스와 (끝 인덱스 -1)을 설정
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
<입력>
# 두번째 원소부터 네번째 원소까지
print(a[1:4])

<출력>
[2, 3, 4]

※ 리스트의 인덱스는 0부터 출발하기 때문에 두번째 원소의 인덱스는 1이 됨
끝 인덱스의 경우 1을 뺀 값의 인덱스까지 처리됨

(3) 리스트 컴프리헨션

  • 리스트를 초기화하는 방법 중 하나
  • 대괄호([ ])안에 조건문과 반복문을 넣는 방식으로 리스트 초기화
# 0부터 19까지의 수 중에서 홀수만 포함하는 리스트
<입력>
array = [i for i in range(20) if i % 2 == 1]
print(array)

<출력>
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

※ 위 코드를 일반적인 소스코드 작성할 경우
<입력>
array = []
for i in range(20):
	if i % 2 == 1:
    	array.append(i)
print(array)
  • 리스트 컴프리헨션을 이용했을 때 소스코드가 훨씬 짧고 간결
# 1부터 9까지의 수의 제곱 값을 포함하는 리스트
<입력>
array = [i * i for i in range(1, 10)]
print(array)

<출력>
[1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 2차원 리스트를 초기화할 때 매우 효과적으로 사용될 수 있음
# N * M 크기의 2차원 리스트 초기화
n = 3
m = 4
<입력>
array = [[0] * m for _ in range(n)]
print(array)

<출력>
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

✍ 언더바(_)는 어떤 역할일까요?

  • 파이썬 자료구조/알고리즘에서는 반복을 수행하되 반복을 위한 변수의 값을 무시하고자 할 때 언더바(_)를 자주 사용
# 1 ~ 9짜지의 자연수를 더할 때
summary = 0
for i in range(1, 10):
	summary += i
print(summary)

# 단순히 "Hello World "를 5번 출력할 때
for _ in range(5):
	print("Hello World ")
    
※ 2번째 코드처럼 언더바(_)를 이용하여 무시할 수 있음

✓ 특정 크기의 2차원 리스트를 초기화할 때는 반드시 리스트 컴프리헨션을 이용해야함

# N * M 크기의 2차원 리스트 초기화(잘못된 방법)
n = 3
m = 4
<입력>
array = [[0] * m] * n
print(array)

array[1][1] = 5
print(array)

<출력>
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 5, 0, 0], [0, 5, 0, 0], [0, 5, 0, 0]]

→ array[1][1]의 값을 5로 바꿨을 뿐인데, 3개의 리스트에서 인덱스 1에 해당하는 원소들의 값이 모두 5로 바뀜
=> 내부적으로 포함된 3개의 리스트가 모두 동일한 객체에 대한 3개의 레퍼런스로 인식되기 때문
∴ 특정한 크기를 가지는 2차원 리스트를 초기화할 때는 리스트 컴프리헨션을 이용해야 한다는 점 기억!!

(4) 리스트 관련 기타 메서드

  • 주요 메서드
<입력>
a = [1, 3, 5]
print("기본 리스트: ", a)

# 리스트에 원소 삽입
a.append(2)
print("삽입: ", a)

# 오름차순 정렬
a.sort()
print("오름차순 정렬: ", a)

# 내림차순 정렬
a.sort(reverse=True)
print("내림차순 정렬: ", a)

# 리스트 원소 뒤집기
a.reverse()
print("원소 뒤집기: ", a)

# 특정 인덱스에 데이터 추가
a.insert(2, 3)
print("인덱스 2에 3 추가: ", a)

# 특정 값인 데이터 개수 세기
print("값이 3인 데이터 개수: ", a.count(3))

# 특정 값 데이터 삭제
a.remove(1)
print("값이 1인 데이터 삭제: ", a)

<출력>
기본 리스트: [1, 3, 5]
삽입: [1, 3, 5, 2]
오름차순 정렬: [1, 2, 3, 5]
내림차순 정렬: [5, 3, 2, 1]
원소 뒤집기: [1, 2, 3, 5]
인덱스 2에 3 추가: [1, 2, 3, 3, 5]
값이 3인 데이터 개수: 2
값이 1인 데이터 삭제: [2, 3, 3, 5]

✓ 이 중 insert(), append(), remove()를 특히 더 눈여겨 두기!!

  • insert()함수를 사용할 때 원소의 개수가 N개면 시간복잡도는 O(N)임
  • append()함수는 O(1)에 수행되는 데에 반해 insert()함수는 동작이 느림(중간에 원소를 삽입한 뒤에 리스트의 원소 위치를 조정해줘야 하기 때문)
    ∴ insert()함수를 남발하면 '시간초과'로 테스트를 통과하지 못할 수도 있음
  • remove()의 시간복잡도는 insert()함수와 마찬가지(insert()함수와 마찬가지로 리스트에서 중간에 있는 원소를 삭제한 뒤 리스트의 원소 위치를 조정해주어야 하기 때문)
    ☑ 특정한 값의 원소를 모두 제거하려면?
    → 다른 프로그래밍 언어에서는 remove_all()과 같은 함수로 간단하게 특정한 값을 가지는 모든 원소를 제거
    → 파이썬의 경우 이러한 함수를 기본적으로 제공해주지 않으므로 다음과 같은 방법을 이용하면 좋음
a = [1, 2, 3, 4, 5, 5, 5]
remove_set = [3, 5]

# remove_set에 포함되지 않은 값만을 저장
result = [i for i in a if i not in remove_set] 
print(result)

※ a에 포함된 원소를 하나씩 확인하며 그 원소가 remove_set에 포함되어 있지 않았을 때만 리스트 변수인 result에 넣겠다는 의미

3. 문자열 자료형

(1) 문자열 초기화

  • 문자열 변수를 초기화할 때는 큰따옴표(")나 작은따옴표(')를 이용
  • 소스코드를 작성할 때 문자열 안에 큰따옴표나 작은따옴표가 포함되어야 하는 경우가 있음
  • 문자열을 큰따옴표로 구성하는 경우 내부적으로 작은따옴표를 포함할 수 있음
  • 문자열을 작은따옴표로 구성하는 경우 내부적으로 큰따옴표를 이용할 수 있음
  • 백슬래시()를 사용하면 큰따옴표나 작은따옴표를 문자열에 원하는 만큼 포함시킬 수 있음

✎ 프로그래밍 문법에서는 백슬래시와 같은 문자를 '이스케이프 문자'로 정해두고 큰따옴표를 출력하는 등의 특별한 목적으로 사용함

<입력>
data = "Don't you know \"Python\"?"
print(data)

<출력>
Don't you know "Python"?

(2) 문자열 연산

  • 문자열에 대한 연산 지원하는데 문자열을 처리할 때 유용
# 문자열 변수에 덧셈(+)을 이용하면 단순히 문자열이 더해져서 연결
<입력>
a = "Hrllo"
b = "World"
print(a + "" + b)

<출력>
Hello World

# 문자열 변수를 양의 정수와 곱하는 경우, 문자열이 그 값만큼 여러 번 더해짐
<입력>
a = "Hello"
print(a * 3)

<출력>
HelloHelloHello
  • 파이썬의 문자열은 내부적으로 리스트와 같이 처리됨
  • 문자열은 여러 개의 문자가 합쳐진 리스트라고도 볼 수 있음
    ∴ 문자열 데이터에 대해서 마찬가지로 인덱싱과 슬라이싱을 이용할 수 있음
<입력>
a = "ABCDEFGH"
print(a[2 : 4])

<출력>
CD

4. 튜플 자료형

  • 튜플 자료형은 리스트와 거의 비슷한데 다음과 같은 차이가 있음
    ☑ 튜플은 한 번 선언된 값을 변경할 수 없음
    ☑ 리스트는 대괄호([ ])를 이용하지만, 튜플은 소괄호(())를 이용
    예) 하나의 튜플 데이터를 선언한 뒤, 값을 출력하고 튜플의 특정한 값 변경
a = (1, 2, 3, 4)
print(a)

a[2] = 7

→ 튜플의 값(1, 2, 3, 4)는 그대로 출력
→ 튜플의 값을 변경하려고 할 때 오류메시지가 출력(오류의 내용 : 원소의 대입이 불가능하다는 메시지)
=> 말 그대로 대입연산자(=)를 사용하여 값을 변경할 수 없다는 의미

  • 튜플 자료형은 그래프 알고리즘을 구현할 때 자주 사용
    예) 다익스트라 최대 경로 알고리즘처럼 최단경로를 찾아주는 알고리즘의 내부에서는 우선순위 큐를 이용하는데 해당 알고리즘에서 우선순위 큐에 한 번 들어간 값은 변경되지 않음
    그래서 그 우선순위 큐에 들어가는 데이터를 튜플로 구성하여 소스코드를 작성
    ※ '비용'과 '노드번호'라는 서로 다른 성질의 데이터를 (비용, 노드번호)의 형태로 함께 튜플로 묶어서 관리하는 것이 관례
  • 알고리즘을 구현하는 과정에서 일부러 튜플을 이용하게 되면 혹여나 자신이 알고리즘을 잘못 작성함으로써 변경하면 안되는 값이 변경되고 있지는 않은지 체크할 수 있음
  • 리스트에 비해 상대적으로 공간효율적, 일반적으로 각 원소의 성질이 서로 다를 때 주로 사용

5. 사전 자료형

(1) 사전 자료형 소개

  • 키(key)와 값(value)의 쌍을 데이터로 가지는 자료형
  • 리스트나 튜플은 값을 순차적으로 저장한다는 특징이 있음
  • 사전 자료형은 키-값 쌍을 데이터로 가진다는 점에서, 우리가 원하는 변경 불가능한 데이터를 키로 사용할 수 있음
    ✎ 변경 불가능한 자료형 : 수 자료형, 문자열 자료형, 튜플 자료형과 같이 한 번에 초기화되면 변경이 불가능한 자료형
    ✎ 흔히 사용되지는 않지만 튜플 자료형이 사전 자료형의 키로 사용되기도 함
  • 사전 자료형이 사용되는 대표적인 예 : 사전(dictionary)
    ☑ 다음과 같이 키-값 쌍으로 구성되는 데이터를 담아야 한다면?
  • 키로 한글 단어를 넣고, 값으로 영어 단어를 넣어 '사과'의 영어 단어를 알고 싶다면 '사과'라는 키 값을 가지는 데이터에 바로 접근하면 됨
    ✓ 키-값 쌍으로 구성된 데이터를 처리함에 있어 리스트보다 훨씬 빠르게 동작한다는 점을 기억!!
<입력>
data = dict()
data['사과'] = "Apple"
data['바나나'] = "Banana"
data['코코넛'] = "Coconut"
print(data)

<출력>
{'사과': 'Apple', '바나나': 'Banana', '코코넛': 'Coconut'}
  • 사전 자료형에 특정한 원소가 있는지 검사할 때는 '원소 in 사전'의 형태를 사용할 수 있음(이는 리스트나 튜플에서도 사용할 수 있는 문법)
    ✎ 리스트, 문자열, 튜플 등 원소들을 차례대로 반복할 수 있는 자료형을 iterable 자료형이라고 함
    ✎ iterable 자료형들은 그 내부에 원소들을 포함하는 컨테이너 역할도 하는 것이 대부분이기에 in 문법도 사용이 가능
<입력>
data = dict()
data['사과'] = "Apple"
data['바나나'] = "Banana"
data['코코넛'] = "Coconut"

if '사과' in data:
	print("'사과'를 키로 가지는 데이터가 존재합니다.")

<출력>
'사과'를 키로 가지는 데이터가 존재합니다.

(2) 사전 자료형 관련 함수

  • 대표적으로는 키와 값을 별도로 뽑아내기 위한 함수
  • keys(): 키 데이터만 뽑아서 리스트로 이용할 때
  • values(): 값 데이터만 뽑아서 리스트로 이용할 때
<입력>
data = dict()
data['사과'] = "Apple"
data['바나나'] = "Banana"
data['코코넛'] = "Coconut"

# 키 데이터만 담은 리스트
key_list = data.keys()

# 값 데이터만 담은 리스트
value_list = data.values()
print(key_list)
print(value_list)

# 각 키에 따른 값을 하나씩 출력
for key in key_list:
	print(data[key])
    
<출력>
dict_keys(['사과', '바나나', '코코넛'])
dict_values(['Apple', 'Banana', 'Coconut'])
Apple
Banana
Coconut

6. 집합 자료형

(1) 집합 자료형 소개

  • 집합(set)을 처리하기 위한 집합 자료형 제공
  • 기본적으로 리스트 혹은 문자열을 이용해 만들 수 있음
    ☑ 중복을 허용하지 않음
    ☑ 순서가 없음
  • 리스트나 튜플은 순서가 있기 때문에 인덱싱을 통해 자료형의 값을 얻을 수 있었으나, 사전 자료형과 집합 자료형은 순서가 없기 때문에 인덱싱으로 값을 얻을 수 없음
  • 집합 자료형에는 키가 존재하지 않고, 값 데이터만을 담게 됨
  • 특정 원소가 존재하는지를 검사하는 연산의 시간복잡도는 사전 자료형과 마찬가지
  • 집합 자료형의 사용방법을 알아두면 효과적으로 이용될 때가 있음
    => 특히, '특정한 데이터가 이미 등장한 적이 있는지 여부'를 체크할 때 매우 효과적
  • 집합 자료형을 초기화할 때는 set()함수 이용하거나, 중괄호({})안에 각 원소를 콤마(,)를 기준으로 구분해서 넣으면 됨
<입력>
# 집합 자료형 초기화 방법 1
data = set([1, 1, 2, 3, 4, 4, 5])
print(data)

# 집합 자료형 초기화 방법 2
data = {1, 1, 2, 2, 3, 4, 4, 5}
print(data)

<출력>
{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5}

(2) 집합 자료형의 연산

  • 기본적인 집합 연산 : 합집합, 교집합, 차집합 연산
  • 합집합 : '|'를 이용
  • 교집합 : '&'를 이용
  • 차집합 : '-'를 이용
<입력>
a = set([1, 2, 3, 4, 5])
b = set([3, 4, 5, 6, 7])

# 합집합
print(a | b)

# 교집합
print(a & b)

# 차집합
print(a - b)

<출력>
{1, 2, 3, 4, 5, 6, 7}
{3, 4, 5}
{1, 2}

(3) 집합 자료형 관련 함수

  • add(): 하나의 집합 데이터에 값을 추가할 때
  • update(): 여러 개의 값을 한꺼번에 추가하고자 할 때
  • remove(): 특정한 값을 제거할 때
  • 이 때, add(), remove() 모두 시간복잡도 O(1)
<입력>
data = set([1, 2, 3])
print(data)

# 새로운 원소 추가
data.add(4)
print(data)

# 새로운 원소 여러 개 추가
data.update([5, 6])
print(data)

# 특정한 값을 갖는 원소 삭제
data.remove(3)
print(data)

<출력>
{1, 2, 3}
{1, 2, 3, 4}
{1, 2, 3, 4, 5, 6}
{1, 2, 4, 5, 6}

<reference(참조)>
나동빈(2020).<이것이 취업을 위한 코딩 테스트다 with 파이썬>.서울: 한빛미디어(주)

0개의 댓글