제가 재학 중인 대학교에서 열린 `파이썬 알고리즘 코딩캠프(25.02.03 ~ 25.02.14)` 수업을 듣고 정리한 글입니다.
목차 :
- 1일차 수업 내용 복습
- 정렬과 람다
- 오름차순&내림차순 정렬
- sorted()
- list.sort()
- 커스텀 정렬
- lambda
- 일급 객체
- 오름차순&내림차순 정렬
- 2차원 리스트
- 2차원 리스트 초기화
- 2차원 리스트 입력
- 2차원 리스트 순회
1일차 수업 내용 복습
컨테이너 자료형들의 분류
순서가 있는 자료형 : 인덱스 접근 가능
순서가 없는 자료형 : 인덱스 접근 불가능
리스트 셋 딕셔너리 : 뮤터블 → 객체는 유지하고 내용을 바꿈
나머지(튜플, 문자열) : 이뮤터블 → 객체 자체가 바뀜, 즉 메모리에 새로 할당됨
리스트
list.pop(i)가 O(N)인건 최악의 경우(pop(0))이면 뒤에 꺼 하나씩 앞으로 밀어야 하니까. insert(i)도 마찬가지.
리스트에 쓰는 in 도 O(N)이라서 주의
a = {1 …} 일 때 list(a) 하면 O(N)임. 빈 리스트 만들고 append를 n번 해야하기 때문.
집합&딕셔너리
set.remove 가 왜 O(1)인가? list.remove는 O(N)인데?
→ 집합은 순서가 없으며 hash table구조이기 때문.
단, set()나 dict로 변환하는 거는 O(N). 빈 집합 만들어서 add.
왜 len()은 리스트든 집합이든 1이냐?
⇒ 파이썬의 구현체 CPython의 구조체 안에, 해당 자료형의 길이를 의미하는 변수가 들어있기 때문.
정렬과 람다 - sorted(), list.sort(), lambda, 일급 객체
오름차순&내림차순 정렬 - sorted(), list.sort()
커스텀 정렬 - lambda, 일급 객체
# 1. 기본 커스텀 정렬
words = ['hello', 'abc', 'z']
print(sorted(words))
def length(word):
return len(word)
print(sorted(words, key=length))
# 주의!! 아래처럼 호출하면 안됨. 순수하게 함수 이름만 넘겨줘야함.
# print(sorted(words, key=length()))
print(sorted(words, key = lambda x:len(x)))
print(sorted(words, key = len))
# 위 코드들은 모두 동일하게 길이 기준으로 정렬함.
# 2. 리스트를 원소로 갖는 리스트 커스텀 정렬
numbers = [ [1, 13], [2, 7], [1, 7], [5, 10], [4, 20] ]
print(sorted(numbers))
# sorted는 2차원 리스트를 정렬할 때, 첫 번째 원소부터 보고,
# 같은 애들은 그 이후 두 번째, 세 번째, ... 끝까지 depth를 보고 정렬.
# 나는 앞에꺼 말고 무조건 뒤에꺼 기준으로 정렬하고 싶어!! 하면 아래처럼 짜면 됨.
def sort_key(unit):
return unit[1]
print(sorted(numbers, key = sort_key))
print(sorted(numbers, key = lambda x: x[1]))
# 근데, 같은 우선순위에 대해선 앞에 거로 또 비교해서 정렬하면 좋겠는데??
def sort_key2(unit):
return unit[1], unit[0] # 이거 반환형 튜플임! 소괄호 생력되어 있는 거.
print(sorted(numbers, key = sort_key2))
print(sorted(numbers, key = lambda x:(x[1], x[0])))
# 함수를 직접 정의하는 것과, 람다를 쓰는 것 둘 다 할 줄 알아야 함!!
# 람다로만 하기에는 복잡한 것도 있기 때문.
# 3. 람다 표현식
# 람다 == 함수 == 일급 객체(First Class Object)
# 아래 세 가지 특성을 만족하는 객체를 '일급 객체'라고 함.
# 즉, 함수는 일급 객체의 특성을 만족하며, 람다도 함수니까 일급 객체임.
# 1) 함수는 변수에 할당할 수 있다.
import sys
input = sys.stdin.readline
# 함수 이름 자체를 변수에 할당해 준 예시.
# 2) 함수는 인자로 넘길 수 있다.
def calculate_length(func):
numbers = [1, 2, 3]
length = func(numbers)
print(length)
calculate_length(len)
# 3) 함수는 반환 될 수 있다.
def get_sum_function():
return sum # sum을 반환함.
numbers = [5, 6, 7]
print(get_sum_function()(numbers))
# print(sum(numbers))와 동일.
# 람다(lambda)
def func1(x):
return len(x)
func2 = lambda x:len(x)
numbers = [1, 2, 3, 4, 5]
print(func1(numbers)) # 5
print(func2(numbers)) # 5
# 계산기 만들기
operator = '+'
a, b = 100, 200
if operator == '+':
print(a + b)
elif operator == '-':
print(a - b)
elif operator == '*':
print(a * b)
else:
print(a / b)
# 이걸 람다를 사용해, 멋있게 구현 가능할까?
calculator = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y,
}
print(calculator[operator](a,b))
print((lambda x, y: x + y)(a, b)) # 이렇게도 가능
2차원 리스트
2차원 리스트 초기화
# 이차원 리스트
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(matrix[1][0])
matrix[1][0] = 10
print(matrix)
'''
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
'''
# 위처럼 0으로 채워진 3x3 행렬로 초기화하고 싶은데, 어떻게 하면 좋을까?
# sol1(
matrix = []
for _ in range(3): #행(row)
line = []
for _ in range(3): # 열(col)
line.append(0)
matrix.append(line)
print(matrix)
# sol2)
matrix = []
for _ in range(3): #행(row)
line = [0 for _ in range(3)]
matrix.append(line)
print(matrix)
# sol3)
matrix1 = [[0 for _ in range(3)] for _ in range(3)]
print(matrix1)
# sol4)
matrix2 = [[0] * 3 for _ in range(3)]
print(matrix2)
# sol5)
matrix3 = [[0] * 3] * 3
print(matrix3)
# 근데... sol5)가 가장 짧으니 저게 젤 좋을까?
# 아무 문제가 없을까?????
matrix1[0][0] = 7
print(matrix1)
matrix2[0][0] = 7
print(matrix2)
matrix3[0][0] = 7
print(matrix3)
# matrix1 = [[0 for _ in range(3)] for _ in range(3)]
# matrix2 = [[0] * 3 for _ in range(3)]
# matrix3 = [[0] * 3] * 3
# matrix3은 얕은 복사로 같은 리스트 [0 0 0]를 가리키는 포인팅 객체가
# 뿅 뿅 뿅 하고 복사됨. [객체1, 객체2, 객체3] 인데 각 객체가
# 동일하게 저 리스트 [0 0 0]을 가리키고 있는거
# matrix2에서 [7 7 7]이 되지 않는 이유는,
# 0은 이뮤터블이라 복사가 되지 않았기 때문.
# => 이거 다시 이해.
2차원 리스트 입력
# 1. 행렬 크기가 미리 주어지는 경우
'''
1 2 3
4 5 6
7 8 9
'''
import sys
input = sys.stdin.readline
# matrix = [list(map(int, input().split())) for _ in range(3)]
# print(matrix)
# 2. 행렬 크기가 입력으로 주어지는 경우
'''
3
1 2 3
4 5 6
7 8 9
'''
# N = int(input())
# matrix = [list(map(int, input().split())) for _ in range(N)]
# print(matrix)
'''
3 4
1 2 3 4
5 6 7 8
9 0 1 2
'''
# N, M = map(int, input().split())
# matrix = [list(map(int, input().split())) for _ in range(N)]
# print(matrix)
# 결국, 열의 개수에 대한 입력은 필요 없음.
# 문제를 잘못 이해했어서 중간에 뻘짓한 코드
# 만약 이걸 그대로 행렬로 하되 빈 자리는 0으로 채우라 하면
# 이렇게 하면 될 거임.
'''
3
1 2 3
4 5 6
7 8 9
'''
'''
matrix = [[0 for _ in range(3)] for _ in range(4)]
for i in range(4):
temp = list(map(int, input().split()))
for j in range(len(temp)):
matrix[i][j] = temp[j]
print(matrix)
'''
'''
3 4
1 2 3 4
5 6 7 8
9 0 1 2
'''
'''
matrix = [[0 for _ in range(4)] for _ in range(4)]
for i in range(4):
temp = list(map(int, input().split()))
for j in range(len(temp)):
matrix[i][j] = temp[j]
print(matrix)
'''
2차원 리스트 순회
# 행 우선 순회 (행순회)
# => => => 로 행 별로 순회하겠다.
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2]
]
'''
1 2 3 4
5 6 7 8
9 0 1 2
'''
for i in range(3):
for j in range(4):
print(matrix[i][j], end = ' ')
print() # 또는 print('')
for i in range(3):
print(*matrix[i])
# default는 아래처럼 됨
# print(*matrix[i], sep = ' ')
print('======')
# 열 우선 순회 (열순회)
# ↓ ↓ ↓ ↓ 로 열 별로 순회하겠다.
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2]
]
'''
1 5 9
2 6 0
3 7 1
4 8 2
'''
# 로 출력되도록 해보자.
for i in range(4): # 열을 기준으로 먼저 보겠다!
for j in range(3):
print(matrix[j][i], end = ' ')
print() # 또는 print('')
print('======')
#또는,
for j in range(4):
for i in range(3):
print(matrix[i][j], end = ' ')
print() # 또는 print('')
# 그냥 아까 행 순회에서, 바깥과 안쪽의 for문을 바꿔주기만 하면 됨.
print('======')
# 이차원 리스트의 총합
matrix = [
[0, 5, 3, 1],
[4, 6, 10, 8],
[9, -1, 1, 5]
]
# 이거 다 더했을 때 값 출력해보자.
total = 0
for i in range(len(matrix)): # 또는 3
for j in range(len(matrix[0])): # 또는 4
total += matrix[i][j]
print(total)
# 위 코드는 행 순회를 해서 풀었지만, 열 순회를 해서 풀 수도 있음.
# 위 코드를 아래처럼 행 단위로 축약해 풀 수 있음.
total = 0
for line in matrix:
total += sum(line)
print(total)
# 위 코드를 아래 한 줄로 더 축약할 수 있음.
print(sum([sum(line) for line in matrix]))
# [sum(line) for line in matrix] <- [9, 28, 14] 와 같은 리스트
# 이걸 더 더 축약하면 아래처럼 됨.
print(sum(map(sum, matrix)))
# map(sum, matrix) <- sum을 matrix의 각 line에다가 적용한 결과인 map 객체
# 강사님 생각엔, 이건 위에 기초적인 것들이 익숙해진 뒤에 쓰자.
# 행렬의 최대값
print(max(map(max, matrix)))
# 행렬의 최소값
print(min(map(min, matrix)))
백준 2738번: 행렬 덧셈
https://www.acmicpc.net/problem/2738
# https://www.acmicpc.net/problem/2738
# 백준 2738번: 행렬 덧셈
# 풀이 1
import sys
input = sys.stdin.readline
# 입력 : 행렬의 크기 NxM
# 그리고 행렬의 원소들
# 출력 : 두 행렬을 합한 결과 행렬
N, M = map(int, input().split())
matrix_A = [list(map(int, input().split())) for _ in range(N)]
matrix_B = [list(map(int, input().split())) for _ in range(N)]
# matrix_sum = []
# for i in range(N):
# line = []
# for j in range(M):
# line.append(matrix_A[i][j] + matrix_B[i][j])
# matrix_sum.append(line)
# 리스트 컴프리헨션을 사용하여 행렬 합 계산
matrix_sum = [[matrix_A[i][j] + matrix_B[i][j] for j in range(M)] for i in range(N)]
for line in range(N):
print(*matrix_sum[line])
# https://www.acmicpc.net/problem/2738
# 백준 2738번: 행렬 덧셈
# 풀이 2 - 더 효율적
import sys
input = sys.stdin.readline
# 입력 : 행렬의 크기 NxM
# 그리고 행렬의 원소들
# 출력 : 두 행렬을 합한 결과 행렬
N, M = map(int, input().split())
matrix_A = [list(map(int, input().split())) for _ in range(N)]
matrix_B = [list(map(int, input().split())) for _ in range(N)]
for i in range(N):
for j in range(M):
matrix_A[i][j] += matrix_B[i][j]
# 언패킹을 활용하여 출력
for line in matrix_A:
print(*line)
과제 및 풀이 정리
<정렬>
https://cuffyluv.tistory.com/138
https://cuffyluv.tistory.com/142 (난이도 hard)
https://cuffyluv.tistory.com/143 (난이도 hard)
https://cuffyluv.tistory.com/146
<2차원 배열>
'Algorithms and Languages > 25-1 파이썬 알고리즘 코딩캠프' 카테고리의 다른 글
[알고리즘 코딩캠프 5일차] 그래프 탐색 알고리즘: DFS, BFS (0) | 2025.02.18 |
---|---|
[알고리즘 코딩캠프 4일차] 스택, 큐, 덱, 그래프 - 인접 행렬, 인접 리스트 (0) | 2025.02.07 |
[알고리즘 코딩캠프 3일차] 2차원리스트 - 회전, 델타 탐색 (0) | 2025.02.07 |
[알고리즘 코딩캠프 1일차] 뮤터블, 얕은 복사, 문자열, 딕셔너리, 시간복잡도, 입력, 출력, 팁, 파이써닉 - 리스트 컴프리헨션, 패킹, 언패킹, enumerate, Counter (0) | 2025.02.03 |