내가 보려고 만든 유용한 도구함 (코테에서 도움됨)
코테 공부하면서 이거 괜찮다 싶은 걸 정리한 글 입니다.
이 글에서는 제가 보기에 알면 편하다 싶은 걸 적은거라 지극히 개인적인 내용입니다. (본인 공부 및 기록용) 😁
행렬
show_matrix
함수는 행렬을 보기 좋게 출력하기 위해 만든 함수입니다. 뒤 예시들에서 많이 쓰이기 때문에 참고하라고 적어뒀습니다.
def show_matrix(mat):
# mat 행렬을 출력합니다.
for i in range(len(mat)):
print(mat[i])
return None
행렬 회전. list와 zip 활용하여
이 코드는 2차원 배열을 다양한 각도로 회전하는 방법을 보여줍니다. 주어진 배열 arr
는 먼저 원본 상태로 출력되고, 이후 zip
함수와 리스트 컴프리헨션을 사용하여 90도, 180도, 270도로 회전된 상태를 출력합니다. show_matrix
함수는 배열의 상태를 시각적으로 표시하는 데 사용됩니다.
Rot90
은 배열을 시계 방향으로 90도 회전시킨 결과입니다.Rot180
은 배열을 180도 회전시킨 결과입니다.Rot270
은 배열을 시계 반대 방향으로 90도(또는 시계 방향으로 270도) 회전시킨 결과입니다.
이러한 회전은 주로 이미지 처리나 행렬 연산에서 유용하게 사용됩니다.
# 회전
print(" Original : ")
arr = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
show_matrix(arr)
print("======================================")
## zip을 사용하여
# 시계 방향으로 90도 회전
print(" Rotate 90 : ")
Rot90 = list(map(list, zip(*arr[::-1])))
show_matrix(Rot90)
print("======================================")
# 180도 회전
print(" Rotate 180 : ")
Rot180 = [a[::-1] for a in arr[::-1]]
show_matrix(Rot180)
print("======================================")
# 270도 회전
print(" Rotate 270 : ")
Rot270 = [x[::-1] for x in list(map(list, zip(*arr[::-1])))[::-1]]
show_matrix(Rot270)
print("======================================")
행렬 회전. index를 활용하여
이 코드는 3x3 행렬을 90도, 180도, 270도로 회전시키는 방법을 보여줍니다. 각 회전은 인덱스 매핑을 통해 수행되며, 결과는 show_matrix
함수를 사용하여 출력됩니다. 초기 행렬 arr
는 1부터 9까지의 숫자로 구성되어 있으며, n
은 행렬의 크기를 나타냅니다. 90도 회전은 각 원소를 (i, j)
에서 (j, n-1-i)
로 이동시키고, 180도 회전은 (i, j)
에서 (n-1-i, n-1-j)
로, 270도 회전은 (i, j)
에서 (n-1-j, i)
로 이동시킵니다. 각 회전 후의 행렬은 새로운 행렬 Rot90
, Rot180
, Rot270
에 저장되어 show_matrix
함수를 통해 출력됩니다.
print(" 원본 : ")
arr = [[1,2,3], [4,5,6], [7,8,9]]
n = 3
show_matrix(arr)
print("======================================")
# 인덱스를 사용한 90도 회전
print(" 90도 회전 : ")
Rot90 = [[0]*n for _ in range(n)]
for i in range(n):
for j in range(n):
Rot90[j][n-1 - i] = arr[i][j]
show_matrix(Rot90)
print("======================================")
# 인덱스를 사용한 180도 회전
print(" 180도 회전 : ")
Rot180 = [[0]*n for _ in range(n)]
for i in range(n):
for j in range(n):
Rot180[n-1 -i][n-1 -j] = arr[i][j]
show_matrix(Rot180)
print("======================================")
# 인덱스를 사용한 270도 회전
print(" 270도 회전 : ")
Rot270 = [[0]*n for _ in range(n)]
for i in range(n):
for j in range(n):
Rot270[n-1 -j][i] = arr[i][j]
show_matrix(Rot270)
print("======================================")
행렬 일부분 회전
이 함수는 5x5 크기의 2차원 리스트에서 특정 위치를 기준으로 3x3 크기의 부분을 90도 회전시키는 기능을 수행합니다. 먼저, random.sample
을 사용하여 1부터 9까지의 숫자 중 무작위로 5개를 선택하여 5x5 크기의 리스트를 생성합니다. 그 후, Rot90_in_board
함수를 사용하여 지정된 위치(loc
)에서 시작하는 3x3 크기의 부분을 시계 방향으로 90도 회전시킵니다. 이 과정에서 copy.deepcopy
를 사용하여 원본 리스트를 변경하지 않고 새로운 리스트에 결과를 저장합니다. show_matrix
함수는 리스트를 시각적으로 표시하는 데 사용됩니다.
# 부분 회전
import random
basic_list = [i for i in range(1,10)]
arr = [random.sample(basic_list, 5) for _ in range(5)] # m, n
print(" Original : ")
show_matrix(arr)
print("======================================")
# 1,1 -> 1,3
# 1,2 -> 2,3
# 1,3 -> 3,3
loc = [1,1]
import copy
def Rot90_in_board(board, loc, size=3):
n = len(board); m = len(board[0])
result = copy.deepcopy(board)
for i in range(size):
for j in range(size):
result[loc[0]+j][loc[1] + size-1 -i] = board[loc[0]+i][loc[1]+j]
return result
show_matrix(Rot90_in_board(arr, loc))
행렬 원소 채우기. 안에서 밖으로
함수 tornado_inout
는 시작점을 중심으로 나선형 패턴을 생성하여 2차원 배열에 값을 할당합니다. 이 함수는 기본적으로 5x5 크기의 배열을 생성하며, 시작점의 값은 1로 설정됩니다. 나선형 패턴은 배열의 중앙에서 시작하여 점차 바깥쪽으로 확장되며, 이동 방향은 우, 상, 좌, 하 순서로 변경됩니다. 각 방향으로의 이동 거리는 점차 증가하며, 이동이 불가능한 지점에 도달하거나 배열의 경계를 벗어나는 경우 함수는 현재까지의 결과를 반환합니다.
# 홀수만 가능
# 안에서 밖으로 나오는 토네이도
# d 바꾸면 방향 전환 가능
def tornado_inout(start=1, n=5):
result = [[0]*n for _ in range(n)]
x = n//2; y = n//2
result[y][x] = start
d_idx = 0
dist = 1
move_count = 0
while True:
for _ in range(dist):
dy, dx = d[d_idx]
ny = y+dy; nx = x+dx
if [ny, nx] == [0, -1]:
return result
start += 1
if ny < 0 or nx < 0 or ny >= n or nx >= n:
return result
result[ny][nx] = start
y = ny; x = nx
move_count += 1
d_idx = (d_idx+1)%4
if move_count == 2:
dist += 1
move_count = 0
return result
result = tornado_inout()
show_matrix(result)
행렬 원소 채우기. 밖에서 안으로
이 함수는 tornado_outin
이며, 시작 값과 행렬의 크기를 인자로 받아, 토네이도 패턴으로 숫자를 채워 넣은 2차원 리스트를 생성한다. 초기 시작 위치는 (0, 0)
이며, 토네이도 패턴은 우, 하, 좌, 상의 순서로 숫자가 증가하며 중앙에 도달할 때까지 이동한다. 중앙에 도달하거나 행렬의 범위를 벗어나면 함수는 생성된 2차원 리스트를 반환한다. 이 과정에서, 각 방향으로의 이동 후 이동 거리가 조정되어, 토네이도가 점점 중앙으로 좁혀 들어가는 패턴을 생성한다.
d = [(1,0), (0,1), (-1,0), (0,-1)]
def tornado_outin(start=0, n=5):
result=[[0]*n for _ in range(n)] # n x n 크기의 2차원 리스트를 0으로 초기화
x, y = 0,0 # 시작 위치를 (0, 0)으로 설정
result[y][x] = start # 시작 위치에 start 값을 할당
dist = 4 # 이동 거리 초기값 설정
d_idx = 0 # 방향 인덱스 초기값 설정
move_count = -1 # 이동 횟수 초기값 설정
while True:
for _ in range(dist):
dy, dx = d[d_idx] # 현재 방향으로의 이동 거리
ny = y + dy; nx = x + dx # 새로운 위치 계산
if (ny, nx) == (n//2, n//2): # 중앙에 도달하면
start += 1
result[ny][nx] = start # 중앙에 start 값을 할당하고 종료
return result
if ny < 0 or nx < 0 or ny >= n or nx >= n: # 범위를 벗어나면 종료
return result
start += 1
result[ny][nx] = start # 새로운 위치에 start 값을 할당
y = ny; x = nx # 위치 업데이트
move_count += 1
d_idx = (d_idx+1)%4 # 방향 전환
if move_count == 2:
dist -= 1 # 이동 거리 감소
move_count = 0
return result
result = tornado_outin()
show_matrix(result)
최대공약수(GCD), 최소공배수(LCM)
이 모듈은 최대공약수(GCD)와 최소공배수(LCM)를 계산하는 함수들을 제공합니다. 단일 숫자 쌍에 대한 계산과 여러 숫자에 대한 계산을 모두 지원합니다.
gcd(n, m)
함수는 두 숫자n
과m
의 최대공약수를 계산합니다. 이 함수는 유클리드 알고리즘을 사용하여 구현되어 있습니다.gcd(*args)
함수는 여러 숫자의 최대공약수를 계산합니다. 이 함수는 내부적으로_gcd
함수를 사용하여 숫자들 사이의 최대공약수를 차례대로 계산합니다.lcm(n, m)
함수는 두 숫자n
과m
의 최소공배수를 계산합니다. 최소공배수는 두 숫자의 곱을 그들의 최대공약수로 나눈 값으로 구합니다.lcm(*args)
함수는 여러 숫자의 최소공배수를 계산합니다. 이 함수는 내부적으로_lcm
함수를 사용하여 숫자들 사이의 최소공배수를 차례대로 계산합니다.
이 함수들은 수학적 계산, 알고리즘 구현 연습, 또는 실제 응용 프로그램에서 유용하게 사용될 수 있습니다.
# 최대공약수(gcd), 최소공배수(lcm)
def gcd(n, m):
if m == 0:
return n
else:
return gcd(m, n%m)
def gcd(n, m):
while m > 0:
n, m = m, n%m
return n
def gcd(*args):
def _gcd(n, m):
while m > 0:
n, m = m, n%m
return n
if len(args) < 2:
return args[0]
else:
n = args[0]
for m in args[1:]:
n = _gcd(n, m)
return n
# n = GCD * a, m = GCD * b
# LCM = GCD * a * b
# LCM = n * m / GCD
def lcm(n, m):
return n//gcd(n, m)*m
def lcm(*args):
def _lcm(n, m):
return n * m //gcd(n, m)
if len(args) < 2:
return args[0]
else:
n = args[0]
for m in args[1:]:
n = _lcm(n, m)
return n
클래스 class
파이썬 코딩을 하면서, 특히 많은 정보를 이용해야 하는 코딩 테스트 문제를 풀 때, 클래스를 사용하면 간단하면서도 하나의 객체로 문제를 해결할 수 있습니다. 클래스는 데이터와 그 데이터를 처리하는 코드를 하나의 논리적 단위로 묶는 방법을 제공합니다. 이는 코드의 재사용성과 가독성을 높이고, 유지보수를 용이하게 합니다.
아래 예시는 person 클래스를 사용한 예시입니다.
# class 특수 메서드
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name}, {self.age}'
def __repr__(self):
return f'Person(name={self.name}, age={self.age})'
def __lt__(self, other):
return self.age < other.age
p = Person('Alice', 30)
print(p.name, p.age) # Alice 30
p = Person('Alice', 30)
print(p) # Alice, 30
p = Person('Alice', 30)
print(repr(p)) # Person(name=Alice, age=30)
p1 = Person('Alice', 30)
p2 = Person('Bob', 25)
print(p1 < p2) # False
Alice 30
Alice, 30
Person(name=Alice, age=30)
False
zip
파이썬의 zip 함수는 여러 이터러블(iterable) 객체를 병렬로 처리할 수 있도록 도와줍니다. 각 이터러블에서 동일한 위치에 있는 요소들을 튜플로 묶어 새로운 이터러블을 생성합니다. zip 함수는 특히 여러 리스트를 동시에 순회해야 할 때 유용합니다.
# zip 사용법
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
list3 = [True, False, True]
zipped = zip(list1, list2, list3)
print(list(zipped)) # [(1, 'a', True), (2, 'b', False), (3, 'c', True)]
[(1, 'a', True), (2, 'b', False), (3, 'c', True)]
names = ['john', 'Bob', 'Charlie']
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f'{name} scored {score}') # john scored 85 ...
특정 원하는 함수/로직으로 순서 정리하기
원하는 로직으로 정렬하기 위해서는 sorted(list, key=lambda x:(x[1], x[0]))도 있고 함수를 만드는 방법도 존재한다. 관련 문제 : 프로그래머스 가장 큰 수
arr = [3, 30, 34]
# 큰 순서로 정렬하되 길이가 다를 시 길이 같게 만들기
def pad_list(lst, max_length):
# 리스트의 길이가 max_length보다 짧으면 마지막 요소로 채움
return lst + [lst[-1]] * (max_length - len(lst))
def custom_sort_key(lst, max_length):
# 리스트를 패딩한 후 튜플로 변환하여 반환
return tuple(pad_list(lst, max_length))
sorted_arr = sorted(lists, key=lambda lst: custom_sort_key(lst, max_length))
from functools import cmp_to_key
def compare(a,b):
if a+b > b+a:
return -1
elif a+b < b+a:
return 1
else:
return 0
def solution(numbers):
numbers = list(map(str, numbers))
numbers.sort(key=cmp_to_key(compare))
answer = ''.join(numbers)
if answer[0] == '0':
return '0'
return answer
행렬이나 복잡한 구조 copy
2차 행렬과 같은 복잡한 자료구조의 복사는 정확하게 하는 것이 중요하다. 단순히 복사했다가 연결되어있어서 문제를 제대로 해결하지 못할 수도 있다.
from copy import deepcopy
arr = [[1,2,3],[4,5,6]]
arr2 = arr.copy()
arr3 = deepcopy(arr)
arr4 = [i[:] for i in arr] # slicing
arr[0][0] = 100
def deepcopy(arr: list): # 이렇게 deepcopy를 구현해도 됨
if type(arr[0]) == int:
return [i for i in arr]
return [line[:] for line in arr]
print(arr) # -> [[100, 2, 3], [4, 5, 6]]
print(arr2) # -> [[100, 2, 3], [4, 5, 6]]
print(arr3) # -> [[1, 2, 3], [4, 5, 6]]
print(arr4) # -> [[1, 2, 3], [4, 5, 6]]
Tree, Tree DP, LCA, Invert Binary Tree MST(Disjoint Set), Kruskal, Prim 위상정렬, Graph DP Manacher 알고리즘, String Hashing, KMP, Trie Bitonic Cycle, BitmaskDP
이것저것 공부하면서 python(특히 코테)에서 유용한 도구들, 코딩들 대해 새로 익히게 되는 내용은 계속 추가할 예정입니다. 궁금한 것들이나 추가 및 수정했으면 좋겠는 거 말해주시면 좋을 거 같아요. 좋은 하루 보내시길 바래요 :)
댓글남기기