이번 주 알고리즘을 공부하면서 가장 크게 느낀 건, 문제를 푸는 속도보다 제대로 이해하고 넘어가는 게 중요하다는 점이다.
처음에는 새로운 문제를 계속 풀어야 실력이 늘 거라고 생각했다. 그런데 문제를 풀다 보니 이전에 공부한 개념도 막상 코드로 옮기려면 헷갈리는 경우가 많았다. 분명 공부했던 내용인데 손이 멈췄다.
그래서 Basic 문제부터 천천히 다시 복습하기로 했다. 몇 문제를 풀었는지보다, 내가 작성한 코드가 왜 동작하는지 설명할 수 있는지를 더 신경 쓰려고 한다.
코드가 똑같이 동작하더라도 내가 이해하기 편한 표현이 있다는 것도 느꼈다. BFS에서 큐를 초기화할 때가 그랬다.
queue = deque([start])처럼 한 줄로 쓰는 것보다, queue = deque()로 빈 큐를 만들고 queue.append(start)로 시작점을 넣는 게 머릿속으로 실행 과정을 그리기 편했다. 큐가 생기고, 그 안에 값이 들어가는 순서가 눈에 보이는 느낌이었다.
짧은 코드를 보면 괜히 더 잘 짠 코드처럼 느껴질 때가 있다. 하지만 지금은 내가 읽고 동작을 따라갈 수 있는 표현으로 쓰는 것이 도움이 된다. 익숙해지면 자연스럽게 줄여 쓸 수 있을 테니, 우선은 이해부터 하기로 했다.
Expert 문제에서는 꽤 자주 막혔다. 208번 Trie와 207번 Course Schedule은 다시 봐야겠다고 적어 두었다. 그래도 300번 LIS는 직접 풀었다. 어려운 문제들 사이에서 혼자 풀어낸 문제가 하나 있으니 반가웠다. 야호 한 번 할 만했다.
5번도 풀기는 했지만 브루트포스로 접근해서, 다음에는 DP로 다시 풀어 보고 싶다. 정답을 맞혔어도 다른 접근을 배울 여지가 남아 있다는 걸 느꼈다.
특히 72번은 어려웠다. 다른 분의 설명을 들었는데, 내가 혼자 고민할 때는 전혀 떠올리지 못했던 방식이었다. 이런 문제는 설명을 듣고 고개를 끄덕이는 것과 직접 생각해 내는 것 사이에 거리가 꽤 크다.
그 일을 계기로 알고리즘 책의 DP 부분을 읽어 보기로 했다. 문제만 계속 바라보고 있어도 생각이 진전되지 않을 때는, 해당 유형의 개념을 다시 읽는 것도 좋은 방법인 것 같다. 다익스트라도 책으로 정리해 볼 내용에 적어 두었다.
DP에서는 계산 결과를 저장해 두고 다시 활용한다는 점이 인상적이었다. 이미 구한 값을 기억하는 데 메모리를 쓰는 대신, 같은 계산을 반복하는 시간을 줄인다. 시간과 메모리의 트레이드오프가 어떤 의미인지 조금 더 구체적으로 와닿았다.
개념을 읽으면 이해되는 것 같지만, 실제 문제에서 무엇을 저장하고 어떤 순서로 계산할지 정하는 건 여전히 어렵다. 앞으로 복습하면서 익혀야 할 부분이다.
공부하면서 이 영상도 도움이 되는 것 같아 기록해 둔다.
리트코드 문제를 계속 풀다 조금 지쳐서 프로그래머스의 DFS/BFS 문제도 풀었다. 타깃 넘버와 네트워크 문제를 보면서 기본적인 탐색 과정을 다시 생각해 볼 수 있었다.
네트워크 문제는 처음에 연결 정보를 별도의 리스트로 정리하려고 했다. 그러다 순환해서 방문하는 건 어떻게 막을지, 리스트와 딕셔너리 중 무엇을 써야 할지 고민이 길어졌다. 결국 핵심은 방문 여부를 기록하고, 연결된 컴퓨터들을 DFS로 탐색하는 것이었다.
구현한 뒤에도 분명 맞는 것 같은데 계속 틀렸다. GPT에게 힌트를 받아 확인해 보니 조건문의 위치가 문제였다.
방문하지 않은 컴퓨터를 발견했을 때 DFS를 시작하고, 그때 네트워크 개수를 하나 늘려야 했다. DFS 한 번으로 연결된 컴퓨터들을 방문하므로, 이후 발견하는 미방문 컴퓨터가 새로운 네트워크의 시작이 되는 구조였다.
이 문제를 풀면서 인덱스와 값을 구분하는 것도 중요하다고 느꼈다. 특히 이차원 배열에서는 지금 보고 있는 것이 컴퓨터 번호인지, 연결 여부를 나타내는 값인지 헷갈리기 쉬웠다. 코드를 쓰기 전에 각 변수가 무엇을 의미하는지 분명히 해야겠다고 생각했다.
리트코드 35번 이진 탐색도 비슷했다. 가운데 값을 보고 탐색 범위를 줄인다는 원리는 이해했는데, 삽입 위치를 찾으려니 경계가 생각보다 헷갈렸다.
원리를 안다고 생각하는 것과 경계까지 정확하게 구현하는 것은 별개의 일이었다. 작은 예시를 두고 인덱스가 어떻게 움직이는지 직접 따라가 보는 연습이 필요하다고 느꼈다.
결국 BFS에서 큐를 초기화할 때 느낀 것과도 연결된다. 코드를 읽고 이해했다고 생각하는 데서 끝내지 않고, 실제로 어떤 순서로 동작하는지 머릿속으로 그릴 수 있어야 한다.
정글에서 공부하면서 좋은 점 중 하나는 가까이에서 다른 사람의 사고 과정을 볼 수 있다는 것이다.
나와 비슷한 부분에서 고민하면서도, 내가 막힌 부분을 먼저 이해한 사람들이 있다. 그분들에게 설명을 들으면 어떤 생각으로 접근했는지 물어볼 수 있고, 그 방식을 직접 따라 해 볼 수도 있다.
나보다 잘하는 사람이 있다는 사실보다, 그 사람이 문제를 풀어 가는 과정을 옆에서 볼 수 있다는 점이 좋았다. 막연하게 느껴졌던 실력이 조금 더 구체적인 목표가 된다.
혼자 공부했다면 답을 보고 넘어갔을 문제도, 옆 사람에게 설명을 들으면서 내가 어떤 생각을 놓쳤는지 돌아보게 된다. 이번 주 DP 문제를 공부하면서 특히 그 점을 느꼈다.
이번 주에는 내가 부족한 부분을 많이 발견했다. 동시에 공부 방식을 어떻게 바꾸면 좋을지도 조금 보였다.
충분히 익히지 못한 채 새로운 문제로 넘어갔던 부분들을 다시 확인하고, 이해한 내용을 직접 코드로 옮겨 보려고 한다.
유형별 공부만 계속하니 지치는 순간도 있어서, 복습을 중심으로 하되 리트코드 오늘의 문제도 하루에 하나씩 풀어 볼 생각이다. 어려운 문제에 막히면 책이나 설명의 도움을 받고, 그렇게 배운 문제는 나중에 혼자 다시 풀어 봐야겠다.
천천히 풀더라도, 다음에 비슷한 문제를 만났을 때 꺼내 쓸 수 있을 만큼 이해하고 넘어가자.
지금 내게 필요한 공부는 그런 방향인 것 같다.
좋은데요?