파이썬 알고리즘 풀이 하면서 느낀점
1. C와 다르게 내부 동작 과정이 많이 생략돼있는 것 같음 -> input output 값에 더 집중해야 할 것 같음
2. 자료형이 표시돼있지 않음 -> 이것 때문인지는 모르겠는데 소스코드가 잘 안읽힘
3. 슬라이싱, range() 엄청 햇갈림 특히 for 문 돌릴 때 시작 값, 종료 값 잘못 작성할 때 많음
4. 각 자료형마다 사용할 수 있는 메서드를 잘 알아둬야 할 것 같음
-> GPT의 답변
C와 다르게 내부 동작 과정이 많이 생략돼있는 것 같음
자료형이 표시돼있지 않음
int, char, int[] 같이 감이 오는데, 파이썬은 a, tmp, result만 있으면 바로 안 보임a보다 nums, cnt, left, right, visited가 읽기 쉬움슬라이싱, range() 엄청 헷갈림
range(start, end)도 end 미포함, 슬라이싱 arr[a:b]도 b 미포함이라 규칙은 일관적이지만, 익숙해지기 전엔 자꾸 틀림각 자료형마다 사용할 수 있는 메서드를 잘 알아둬야 할 것 같음
for문 사용시 배열 인덱스
-> GPT의 팁
인덱스가 헷갈릴 때는 숫자를 따라가지 말고, 그 숫자가 가리키는 역할을 따라가면 됨
i, j는 그냥 숫자임
i+1을 보면 “그래서 이게 뭐지?”가 됨
예를 들면
for i in range(n):
if arr[i] < arr[i+1]:
...
이걸 읽을 때 머릿속에서는 사실 이렇게 해석해야 함
i = 현재 위치i+1 = 다음 위치근데 코드에는 “현재”, “다음”이라는 의미가 안 적혀 있으니까
매번 숫자를 계산하면서 읽게 됨
그래서 피곤함
초보 때 가장 흔한 혼동이 이거임
i는 인덱스arr[i]는 값근데 읽다 보면 i 자체를 값처럼 느끼거나
arr[i+1]를 볼 때 “다음 인덱스”와 “다음 값”이 한꺼번에 떠올라서 꼬임
예:
for i in range(len(arr)-1):
print(i, arr[i], arr[i+1])
여기서 동시에 관리해야 하는 게 3개임
iarr[i]arr[i+1]그래서 뇌 부담이 커짐
인덱스 관련 실수는 머릿속 계산만으로 버티면 거의 틀리기 쉬움
특히 반복문 안에서 조건까지 있으면 더 그럼
예:
for i in range(1, n-1):
if arr[i-1] < arr[i] < arr[i+1]:
...
이건 사실
을 비교하는 건데
코드상으로는 i-1, i, i+1이라 숫자 계산처럼 보여서 어려운 거임
이게 제일 중요함
arr[i]
arr[i+1]
이걸
으로 번역해서 읽는 습관 들이면 좋음
예:
for i in range(len(arr)-1):
if arr[i] > arr[i+1]:
...
이걸 그냥
i번째 값i+1번째 값으로 보지 말고
으로 읽기
그러면 훨씬 덜 꼬임
반복문 볼 때 바로 본문부터 보지 말고
먼저 range()가 어디까지 도는지 확인해야 함
for i in range(len(arr)-1):
이 뜻은
i는 0부터 len(arr)-2까지 돈다i+1은 최대 len(arr)-1까지 가능하다arr[i+1]까지 안전하게 접근하려고 -1 한 거다이렇게 먼저 이해하면 본문이 쉬워짐
즉, 반복문 볼 때는 항상 먼저 확인:
i+1이 나오면 “왜 +1이 필요한지” 먼저 보기+1, -1은 대부분 이유가 정해져 있음
arr[i+1]
→ 현재 기준으로 다음 칸 확인
arr[i-1]
→ 현재 기준으로 이전 칸 확인
print(i+1)
→ 내부 인덱스는 0부터 시작하지만, 사람에게는 1번부터 보여주려고 함
for j in range(i+1, n):
→ i 다음 위치부터 비교하려는 것
즉 +1은 뜬금없는 계산이 아니라
대부분 다음 것, 중복 제거, 출력 보정 중 하나임
헷갈리는 문제는 5개짜리 배열로 직접 써보는 게 제일 빠름
실전에서 제일 강력한 방법임
for i in range(len(arr)-1):
print("i =", i, "현재 =", arr[i], "다음 =", arr[i+1])
이렇게 출력하면
인덱스와 값이 어떻게 움직이는지 눈으로 보임
i, j가 동시에 나오면 머릿속에서 선형으로 추적하기 어려움
이때는 표나 좌표처럼 생각하는 게 좋음
예:
for i in range(n):
for j in range(i+1, n):
...
이건 보통
i보다 뒤에 있는 것만 비교의미임
n=4면 실제로는
i=0 → j=1,2,3i=1 → j=2,3i=2 → j=3i=3 → 없음이렇게 됨
즉 (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)만 보는 구조임
이걸 표로 한번 그려보면 훨씬 쉬움
가능하면 숫자 대신 의미를 드러내는 이름으로 바꾸는 게 좋음
예:
for i in range(len(arr)-1):
current = arr[i]
nxt = arr[i+1]
if current > nxt:
...
이렇게 하면
arr[i]arr[i+1]를 계속 읽지 않아도 됨
가독성이 확 좋아짐
2포인터도 비슷함
left, right = 0, len(arr)-1
while left < right:
...
이건 i, j보다 훨씬 덜 헷갈림
왜냐하면 역할이 이름에 들어있기 때문임
숙련되면 매 순간 값을 다 계산하지 않음
대신 규칙을 잡음
예:
for i in range(len(arr)-1):
여기서는
i는 현재 위치i+1은 항상 다음 위치이 규칙만 잡으면 매번 계산 안 해도 됨
2중 반복문도 마찬가지
for i in range(n):
for j in range(i+1, n):
규칙:
j는 항상 i보다 큼이런 규칙을 이해하면 숫자 따라가는 부담이 줄어듦
for i in range(n):
print(i+1, arr[i])
해석:
반복문 보면 먼저 한글로 바꾸기
for i in range(len(arr)-1):
→ “0부터 마지막 바로 전까지”
for j in range(i+1, n):
→ “i 다음 칸부터 끝까지”
이렇게 번역해두면 좋음
본문 읽을 때 역할로 바꾸기
arr[i] → 현재arr[i+1] → 다음arr[i-1] → 이전헷갈리면 4~5개짜리 예시 대입하기
출력 찍어서 실제 값 보기
=
a = [1, 2]
b = a
b[0] = 3
print(a) ---> [3, 2]
.copy()
a = [1, 2]
b = a.copy()
b[0] = 3
print(a) ---> [1, 2]
# 주의 이중 리스트인 경우는 다름. 겉 리스트만 복사 리스트 내부는 참조
a = [[1, 2], [3, 4]]
b = a.copy()
b[0][0] = 5
print(a) ---> [[5, 2], [3, 4]]
copy.deepcopy()
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)
b[0][0] = 5
print(a) ---> [[1, 2], [3, 4]]
깊은 복사 얕은 복사 확인 방법 -> id() 사용
print(id(a)) ---> id값을 비교해서 같은지 다른지 확인
= 인 경우 → id(a) == id(b)
.copy() 인 경우 → id(a) != id(b)
하지만 얕은 복사는 겉만 다르고 속은 같을 수 있음
인덱스로 내부 값도 비교 가능
print(id(a[0]), id(b[0]))