컴퓨터 공부/🧮 알고리즘

[코테] 코딩 테스트 합격자 되기 1주차 - 코딩 테스트 필수 문법

letzgorats 2024. 1. 7. 23:00

이번 포스팅에서는 파이썬 기초 문법을 충실히 설명하기보다는 코딩 테스트에 자주 사용하는 문법을 설명하는 데 집중합니다. 

📖 빌트인 데이터 타입?

    빌트인 데이터 타입(built-in data type)은 언어 자체에서 제공하는 데이터 타입컬렉션 데이터 타입이 있습니다.

    기본 데이터 타입으로는 정수형(Int), 부동소수형(Float), 문자열 타입이 있고

    컬렉션 데이터 타입으로는 리스트, 튜플, 셋, 딕셔너리 등이 있습니다.

   

    1) 정수형

        - 정수형은 양과 음의 정수, 0을 포함합니다. 여러가지 연산을 할 수 있죠.

 

    - 정수형 변수 선언

a = 13
b = 4

   

    - 정수형 산술 연산

print(a+b)    # 더하기 17
print(a-b)    # 빼기 9
print(a*b)    # 곱하기 52
print(a/b)    # 나누기(소수점 포함) 3.25
print(a//b)   # 나누기(소수점 제외-버림) 3

print(a%b)     # 모듈러 연산(나머지) 1
print(-a)      # 부호를 바꿈 -13
print(abs(-a)) # 절댓값 13
print(a**b)    # a의 b승 28561

   

     - 정수형 비교 연산

print(a==b)    # 같은 값인지 비교 - False
print(a!=b)    # 같지 않은 값인지 비교 - True
print(a>b)     # 왼쪽 값이 더 큰지 비교 - True
print(a<b)     # 왼쪽 값이 더 작은지 비교 - False
print(a>=b)    # 왼쪽 값이 더 크거나 같은지 비교 - True
print(a<=b)    # 왼쪽 값이 더 작거나 같은지 비교 - False

   

    - 정수형 비트 연산

print(a&b)    # AND - 4
print(a|b)    # OR - 13
print(a^b)    # XOR - 9
print(~a)     # NOT - -14
print(a<<2)   # 왼쪽 시프트 (a 에 2^2 를 곱한 것과 동일) - 52
print(a>>1)   # 오른쪽 시프트 (a를 2^1로 나눈 것과 동일) - 6

   

    - 정수형 논리 연산

print(a and b)  # 논리 연산 AND - 4
print(a or b)   # 논리 연산 OR - 13
print(not a)    # 논리 연산 not - False

   

    2) 부동소수형

        - 부동소수형은 소수를 저장할 때 사용합니다. 부동소수형도 예시를 통해 살펴봅시다.

 

    - 부동소수형 사칙 연산

print(2.5 + 3.7)    # 더하기 - 6.2
print(7.9 - 4.2)    # 빼기 - 3.7
print(1.5 * 4.8)    # 곱하기 - 7.199999999999999
print(10.0 / 3.2)   # 나누기 - 3.125

   

    - 부동소수형 정수형 나누기, 모듈러, 제곱 연산

print(10 // 3.2)     # 정수형 나누기 - 3.0
print(10.0 % 3.2)    # 모듈러 - 0.39999999999999947
print(2.0 ** 3.2)    # 제곱 연산 - 9.18958683997628

   

     - 부동소수형 논리 연산

x = 0.5
y = 1.2
z = 2.0
print(x > y and y < z)    # AND 연산 - False
print(x < y or y < z)     # OR 연산 - True
print(not (x>y))          # NOT 연산 - True

   

부동소수형 코드 실행 결과를 보면 눈에 띄는 내용이 있습니다. 10 % 3.2 의 연산 결과를 보면, 결괏값이 0.4 가 아니라 0.39999999999999947 입니다.

 

앱실론을 포함한 연산에 주의하자!

- 이런 이유는 파이썬은 부동소수형 데이터를 이진법으로 표현하기 때문입니다. 표현 과정에서 오차가 발생하는 것인데, 이를 앱실론(epsilon) 이라고 합니다.

- 코딩테스트에서 부동소수형 데이터를 다룰 일이 생겼을 때, 이 앱실론을 항상 생각합시다. 부동소수형을 사용하여 코드를 작성하면, 앱실론이라는 요소 때문에 일부 테스트 케에스가 통과하지 못할 수도 있으니 유의해야 합니다.

 

import sys

# epsilon 출력
print(sys.float_info.epsilon)    # 2.220446049250313e-16

# 부동소수점 수의 오차 검사
a = 0.1 + 0.1 + 0.1
b = 0.3

print(a-b)    # 5.551115123125783e-17
if abs(a-b) < sys.float_info.epsilon:
    print("a와 b는 같은 값입니다.")    # 이 코드가 출려됨.
else:
    print("a와 b는 다른 값입니다.")

 

마찬가지로, 0.1을 3번 더한 a의 값에서 0.3을 빼면 0 이 아닙니다. 부동소수형 데이터를 활용하는 문제는 오차 허용 범위를 언급하는 경우가 많습니다. 꼭 문제를 풀 때 체크해야 하는 부분입니다.

 


 

📖 컬렉션 데이터 타입

    컬렉션은 여러 값을 담는 데이터 타입을 말합니다. 대표적으로는 리스트(list), 튜플(tuple), 딕셔너리(dictionary), 셋(set), 문자열(string) 등이 있습니다. 그리고 이 컬렉션들은 데이터의 수정 가능 여부에 따라 변경할 수 있는 객체(mutable object)변경할 수 없는 객체(immutable object) 로 나뉩니다.

 

    1) 변경할 수 있는 객체(뮤터블 객체)

 

        ■ 뮤터블 객체는 객체 생성 후 객체를 수정할 수 있습니다. 대표적인 뮤터블 객체로는 리스트, 딕셔너리, 셋 입니다.

my_list = [1,2,3,4,5]    # 리스트 객체 생성, [1,2,3,4,5]
my_list[4] = 6           # 리스트 원소 변경
print(my_lsit)           # [1,2,3,4,6]

 

위 코드에서는 my_list가 참조하고 있는 [1,2,3,4,5] 에서 5번째 위치에 있는 값 5(인덱스상으로는 4인 위치)를 6으로 수정합니다. 

 

    2) 변경할 수 없는 객체(이뮤터블 객체)

 

        ■ 이뮤터블 객체는 생성 후 객체를 수정할 수 없습니다. 대표적인 이뮤터블 객체는 문자열, 튜플 입니다.

 

이처럼, 뮤터블 객체와 이뮤터블 객체는 값의 수정 유무의 특징이 있으므로 동작하는 방식이 다릅니다.


1) 리스트(list)

        - 리스트는 뮤터블 객체로 [대괄호]로 원소를 감싸는 형태로 사용합니다. 다음 코드를 보면, 리스트의 동작 방식을 쉽게 알 수 있습니다. 흔히 '시퀀스(순서)'가 있는 자료형이라고 말합니다. 이런 특징으로 리스트는 인덱싱, 슬라이싱을 할 수 있습니다.

# list 선언
my_list = [1,2,3,4,5]
my_list2 = [1,3,5] + [7,9]
my_list3 = liast(my_list)

print(my_list)     # [1,2,3,4,5]
print(my_list2)    # [1,3,5,7,9]
print(my_list3)    # [1,2,3,4,5]

 

1-1) 리스트 인덱싱

- 인덱싱은 인덱스를 활용해서 특정 위치의 원소에 접근하는 것을 말합니다. 예를 들어, 다음 코드에서 리스트의 세 번째 값(인덱스 상 2번 인덱스)에 접근하는 my_list[2] 코드를 작성했는데, 이를 '인덱싱으로 원소에 접근한다' 라고 표현합니다.

my_list = [1,2,4]

# 값 추가
my_list.append(6)
print(my_list) # [1,2,4,6]

# 인덱싱으로 값 삭제
del my_list[2] # del 은 인덱스 위치에 있는 원소를 지우는 키워드임.
print(my_list) # [1,2,6]

 

1-2) 리스트 슬라이싱

- 슬라이싱은 시퀀스 자료형의 범위를 지정해서 값들을 복사하여 가져오는 방식을 말합니다. 파이썬 코드로는 list_name[a:b] 와 같이 작성합니다. 이렇게 작성한 코드는 인덱스 a 이상부터 b 미만에 해당하는 원소를 새 리스트에 담아 반환합니다.

my_list = [1,2,3,4,5]

print(my_list[0:2]) # [1,2]
print(my_list[1:]) # [2,3,4,5]
print(my_list[3:4]) # [4]
print(my_list[-4:-2]) # [2,3] - 음수는 뒤에서부터 -1,-2,-3..순

 

2) 딕셔너리(dictionary)

        - 딕셔너리는 뮤터블 객체이며 키(key) 와 값(value) 쌍으로 해시 테이블을 구성합니다. 이름 그대로 키를 사용하여 값을 검색하는 자료형으로 {중괄호}로 초기화를 합니다.

my_dict = {}

 

2-1) 딕셔너리 삽입과 출력

my_dict['apple'] = 1
my_dict['banana'] = 2
my_dict['orange'] = 3

# 딕셔너리 값 출력
print(my_dict)    # {'apple' : 1 , 'banana' : 2, 'orange' : 3}

 

2-2) 딕셔너리 검색

(ex) my_dict가 참조하는 딕셔너리의 키들을 보면서 'apple' 문자열이 일치하는지 확인하고, 일치하는 키를 찾으면 키,값을 출력합니다.

key = 'apple'
if key in my_dict:
    value = my_dict[key]
    print(f"{key} : {value}")    # apple : 1
else:
    print(f"{key}는 딕셔너리에 존재하지 않습니다.")

 

2-3) 딕셔너리 수정

(ex) 키 'banana'를 검색하여 해당 키의 값을 4로 바꿉니다.

my_dict["banana"] = 4
print(my_dict)    # {'apple' : 1, 'banana' : 4, 'orange' : 3}

 

 

2-4) 딕셔너리 삭제

(ex) 키 'orange'를 찾아 딕셔너리에서 삭제합니다.

del my_dict["orange"]
print(my_dict).   # {'apple' : 1 ,'banana' : 4}

 

3) 튜플(tuple)

        - 튜플은 이뮤터블 객체로 리스트, 딕셔너리와 달리 한 번 생성하면 변경을 할 수 없습니다. (소괄호)를 사용해 초기화합니다.

my_tuple = ()

 

3-1) 튜플 인덱싱, 슬라이싱

→ 튜플은 수정이 안되지만, 인덱싱과 슬라이싱은 할 수 있습니다. 문법 자체는 리스트와 동일합니다. 리스트와는 다르게 값을 바꿀 수 없으므로 코딩테스트에서는 값이 변경되지 않는 데이터에 대해 적용해 실수를 방지할 수 있습니다.

my_tuple = (1,2,3)

# 인덱싱
print(my_tuple[0])    # 1
print(my_tuple[1])    # 2
print(my_tuple[2])    # 3

# 슬라이싱
print(my_tuple[1:])     # (2,3)
print(my_tuple[:2])     # (1,2)
print(my_tuple[1:2])    # (2,)

 

4) 문자열(string)

        - 스트링은 문자들의 집합으로 이루어진 이뮤터블 객체입니다. "큰따옴표"나 '작은따옴표'로 감싸 사용합니다.

my_string  = "Allu Coing!"    # 큰 따옴표 사용
my_string2 = 'Allu Coing!'    # 작은 따옴표 사용

 

4-1) 문자열 추가, 삭제

→ 문자열은 이뮤터블 객체이므로 기존 객체를 수정하는 것이 아니라 새로운 객체를 반환한다는 사실입니다. 즉, 기존 문자열을 참조하는 것이 아니라, 새로운 문자열을 만들고 그 문자열을 참조합니다.

my_string = "Allu"
my_string += " Coding"
print(my_string)    # Allu Coding

 

4-2) 문자열 수정

→ 문자열을 수정하고 싶다면, replace 메서드를 사용하면 됩니다. replace() 메서드는 첫 번째 인수로 찾을 문자열을, 두 번째 인수로 변경할 문자열을 넣어 사용합니다. 세 번째 인수로는 변경할 횟수가 들어가는데, 아무값도 안 넣으면 해당하는 문자열을 모두 replace 해줍니다.

my_string = "Allu"
my_string = my_string.replace("l","")    # 'l'을 모두 삭제
print(my_string)    # Au

📖 함수

파이썬의 함수는 def 라는 예약어를 사용하여 정의합니다.

def function_name(param1,param2,param3,...,paramN):
    # 함수의 실행 코드
    # ...
    # ...
    return result # 반환값

 

📖 함수 호출

함수를 정의했으면, 함수를 호출할 수 있습니다. 함수를 호출할 때, 매개변수가 있는 경우 func(a,b) 와 같이 인수를 함께 전달합니다.

def product(num1,num2):
    result = num1 * num2
    return result 

# 함수를 호출하고 결과 실행
answer = product(5, 10)
print(answer) # 50

 

📖 람다식 (lambda expression)

파이썬은 람다식(lambda expression)을 사용할 수 있습니다. 람다식은 함수를 더 간단하게 표현하는 방법인데, 익명함수(anonymous function)를 만드는 데 목적이 있습니다. 

익명 함수란 말 그대로 이름이 없는 함수를 말하며 코드에서 딱 한 번 실행할 목적으로 사용하거나, 다른 함수의 인수로 사용하는 데 사용합니다.

lambda 식

 

→ 람다식 정의는 다음과 같이 정의합니다.

lambda x,y : x + y    # x와 y를 받아서, 더한 값을 반환하는 람다식

 

 

→ 람다식은 2가지 패턴으로 자주 사용합니다.

 

 

1) 변수로 참조할 수 있습니다.

 

■ 그래서 변수에 람다식을 할당하고 람다식 실행이 필요한 경우 변수 (a,b)와 같이 호출할 수 있습니다.

# 람다를 이용한 간단한 함수 정의
add = lambda x,y : x+y
print(add(5,4))   # 9

 

2) 인수로 람다식을 넘기는 방법입니다.

 

■ 정수형 리스트를 하나 선언하고, map() 함수에 람다식을 넘깁니다. 이렇게 하면, map()함수는 두 번째 인수로 넘어온 리스트 첫 번째 인수로 받은 람다식을 적용하여 num의 원소를 각각 제곱한 새 리스트를 반환합니다. 보통 뒤에는 튜플이나 리스트가 와야 한다.

num = [1,2,3,4,5]
squares = list(map(lambda x: x**2,num))
print(squares)    # [1,4,9,16,25]

 

map, filter, reduce, sorted 등과 같이 다양하게 사용할 수 있습니다.

mylist = [1, 2, 3, 4, 5]
mylist2 = list(filter(lambda x: x % 2 == 1, mylist))
print(mylist2)  # [1,3,5]
mylist = ['apple', 'bananas', 'cherry']
mylist2 = sorted(mylist, key=lambda x: len(x))
print(mylist2)   # ['apple', 'cherry', 'bananas']
from functools import reduce

mylist = [1, 2, 3, 4, 5]
result = reduce(lambda x, y: x * y, mylist)
print(result)    # 120

📖 코딩 테스트 코드 구현 노하우

코딩테스트를 처음 공부하면 만나는 첫 난관은 "구현"입니다. 다른 자료구조와 알고리즘에 비해 많이 풀어봐야 구현실력도 향상합니다.

이런 구현에 있어서 노하우를 몇 가지 소개하겠습니다.

 

→ 조기 반환 (early return)

 

■ 조기 반환(early return)은 코드 실행 과정이 함수 끝까지 도달하기 전에 반환하는 기법입니다. 이 방식은 코드의 가독성을 높여줄 뿐만 아니라, 예외를 조금 더 깔끔하고 빠르게 처리할 수 있습니다.

def total_price(quantity, price):
    total = quantity * price
    if total > 100:
        return total * 0.9
    return total
    
print(total_price(4,50))

 

→ 보호 구문 (guard clauses)

 

■ 보호 구문(guard clauses)은 본격적인 로직을 진행하기 전 예외 처리 코드를 추가하는 기법입니다. edge 케이스를 거르는 느낌인 것이죠. 예외처리가 습관이 될 수 있도록 해야 합니다.

def calculate_average(numbers):
    if numbers is None:    # 값이 없으면 종료(예외)
        return None
    
    if not isinstance(numbers,list):    # numbers가 리스트가 아니면 종료(예외)
        return None
        
    if len(numbers) == 0:    # numbers 길이가 0이면 종료(예외)
        return None
    
    total += sum(numbers)
    average = total / len(numbers)
   
   	return average

→ 합성 함수 (composite method)

 

합성 함수 (composite method)는 2개 이상의 함수를 활용하여 함수를 추가로 만드는 기법입니다. 보통 함성 함수는 람다식을 이용합니다. 두 함수를 마치 하나의 함수를 호출하는 것 처럼 사용할 수 있습니다.

def add_three(x):
    return x + 3

def square(x):
    return x * x
    
composed_function = lambda x : square(add_three(x))
print(composed_function(3))    # 36

 


💡파이썬의 빌트인 데이터 타입은 기본타입과 컬렉션 타입이 있다.

 

💡파이썬의 데이터 타입은 이뮤터블 타입과(값 변경x) 뮤터블 타입(값 변경 o) 으로 나뉠 수 있다. 대표적인 뮤터블 타입으로는 리스트, 딕셔너리, 셋이 있고, 이뮤터블 타입으로는 기본타입, 문자열, 튜플 등이 있다.

 

💡함수는 프로그램의 기본 구성요소로 파이썬에서는 def 라는 예약어를 사용한다.

 

💡람다식은 간결한 함수 표현 방법으로, 코드 상에서 한 번만 사용하거나 인자로 함수를 넘겨야 할 때 유용하다.

 

💡구현을 할 때, 조기반환, 보호구문, 합성 함수 등의 기법을 활요해 코드의 가독성과 효율성을 높일 수 있다.


 

반응형