문과생도 이해하는 알고리즘 강의를 가르치는 강사 개발자로 취직하기입니다 :)
저는 문과생 출신으로 현재는 8년차 대기업 개발자입니다. 처음 코딩을 접하고 코딩 테스트 준비를 하던 막막한 시절을 떠올리며, 어떻게 하면 조금 더 쉽게 설명할 수 있을지, 저 같은 비전공자 문과생도 이해하고 새로운 기술을 습득할 수 있을지 고민하며 강의를 제작하고 있습니다.
유튜브 통해서도 무료 강의 진행하고 있으니 많은 관심 부탁 드립니다!
https://www.youtube.com/@gaebal
講義
受講レビュー
- [Java/Java] 文科生も理解するDFSアルゴリズム!
- [Java/Java] 文科生も理解するDFSアルゴリズム!
- [Python/Python] 文科生も理解するDFSアルゴリズム! - 入門編
投稿
Q&A
dfs 부문을 이렇게 작성해도 되나요?
네, 잘 작성하셨습니다. DFS 코드는 문제 없이 정상적으로 동작합니다. 차이점을 이미 잘 아시겠지만 정리하자면: 제 코드(ver 1): 이동할 방향(dirY, dirX)을 배열로 정의하고, for문으로 상하좌우를 탐색합니다. 이 방식은 이동 가능한 방향이 많을 때 코드를 간결하게 작성할 수 있습니다.작성하신 코드: if문을 사용해 아래(y + n)와 오른쪽(x + n) 방향을 각각 따로 확인하고 있습니다. 이 방법도 문제에서는 동일하게 동작하고, 오히려 더 직관적으로 이해하기 쉽습니다. 두 방식 모두 visited 배열을 활용하기 때문에 논리적으로 완벽하며, 결과에도 차이는 없습니다.
- 1
- 1
- 15
Q&A
x랑 y를 거꾸로 쓰는 개념이 너무 헷갈립니다...
안녕하세요, 저도 처음 접했을 때 이 부분이 많이 헷갈렸어서 두 가지 답변을 드려볼게요:) 우선 변수를 서로 바꾸는 것은 전혀 문제 없습니다. 아시다시피 변수명은 문법적 오류만 없으면 컴퓨터는 전혀 신경을 쓰지 않으니 본인이 이해하기 편한 코드를 짜는 것이 가장 중요합니다.다만 대부분의 분들이 이러한 표기법을 사용해서 저도 같은 방식으로 작성하고 있고, 추후에 취업이 되신다면 모두가 이해할 스 있는 읽기 좋은 코드도 중요해집니다.아직은 이것까지 고민하실 때는 아니니 본인이 직관적으로 이해할 수 있는 코드/변수명을 사용하시길 권장드립니다!
- 1
- 2
- 18
Q&A
dfs 파라미터에 count를 넣는이유
안녕하세요, 우선 두번째로 이부분에 정리하신 내용이 맞습니다!아니면 answer로 하면 단순 dfs 함수 호출 횟수를 늘리는거고, 이 문제의 본질은 트리의 depth를 물어보는거가 되는거고 그래서 count로 depth를 알려주는건가 싶습니다 자세하게 부연 설명을 추가하면 이렇습니다.dfs 함수에 count 파라미터를 넣는 이유는 현재 노드까지의 거리를 추적하기 위함입니다. answer 변수를 단순히 전역으로 선언하고 dfs 함수 내부에서 answer++를 하는 방식은 올바른 촌수를 계산하지 못할 수 있습니다.이유:올바른 촌수(거리) 계산: 이 문제는 시작 노드에서 목표 노드까지의 가장 짧은 거리를 찾는 것입니다. dfs(idx, count)처럼 재귀 호출 시 count + 1을 파라미터로 넘겨주면, 각 함수 호출마다 현재 노드까지의 거리가 정확하게 계산됩니다.전역 변수 문제: 만약 answer를 전역 변수로 두고 answer++를 한다면, 재귀 호출이 끝난 후 다른 경로를 탐색할 때 answer 값이 그대로 유지되어 올바르지 않은 값이 나올 수 있습니다. 예를 들어, dfs 함수가 깊이 3까지 들어갔다가 백트래킹(backtracking)을 할 때, answer 값은 3이 된 상태로 남아있게 됩니다. 새로운 경로를 탐색할 때 이전에 증가한 answer 값부터 시작하게 되므로, 정확한 거리를 계산할 수 없습니다.지역적 범위와 재귀의 특징: count 파라미터는 함수 호출 시마다 독립적인 값으로 전달됩니다. 이는 각 재귀 호출이 자신의 count 값을 가지게 되어, 여러 탐색 경로가 서로 영향을 주지 않고 독립적으로 거리를 계산할 수 있게 해줍니다. 즉, 한 경로가 실패하여 돌아오더라도 다른 경로를 탐색할 때 초기 상태인 0부터 다시 시작할 수 있습니다.결론적으로, count 파라미터는 dfs가 재귀적으로 여러 경로를 탐색하는 과정에서 각 경로의 깊이(거리)를 정확하게 측정하기 위한 필수적인 요소입니다.
- 1
- 2
- 19
Q&A
graph 채울때 for문 설계 질문
안녕하세요 dnrwls91152585님 :)두 for문은 역할이 완전히 다릅니다. 하나는 그래프의 '틀'을 만드는 초기화용이고, 다른 하나는 그 틀에 간선 '내용'을 채우는 용도입니다.for (int i = 1; i 루프의 역할이 코드는 정점의 개수(N)만큼 반복하면서, 각 정점에 연결될 간선들을 저장할 빈 ArrayList를 만들어주는 역할을 합니다.graph = new ArrayList[MAX] 라고 선언만 하면 graph의 각 칸은 비어있는 상태(null)라서, 이 과정을 거치지 않고 graph[i].add()를 호출하면 오류가 납니다.즉, N개의 정점 각각에 대해 "이제부터 여기에 간선을 저장할 수 있어"라고 준비시켜주는 단계입니다.문제에서 노드의 번호를 0 ~ N-1이 아닌 1 ~ N까지로 정의했기 때문에 1 부터 N을 포함한 지점까지 반복하도록 정의했습니다.for (int i = 0; i 루프의 역할이 코드는 간선의 개수(M)만큼 반복하면서, 입력으로 주어진 간선 정보를 읽어옵니다.u v를 읽어서, 위 1번 과정에서 만들어 둔 graph[u] 리스트에 v를 추가하고, graph[v] 리스트에 u를 추가하는 일을 합니다.미리 준비된 공간에 실제 데이터를 채워 넣는 단계라고 보시면 됩니다.요약하자면, 첫 번째 N번 반복하는 루프는 N개의 빈 서랍(리스트)을 만드는 작업이고, 두 번째 M번 반복하는 루프는 M개의 서류(간선)를 해당 서랍에 넣는 작업이라고 생각하시면 쉽습니다. 그래서 하나는 정점 수(N)를 기준으로, 다른 하나는 간선 수(M)를 기준으로 반복하는 것입니다.
- 1
- 2
- 19
Q&A
질문있습니다.
안녕하세요 eovnfjfpa4963님!말씀하신 대로 N 이 큰 경우 ArrayList를 사용하는 것이 기본적인 원칙인데, 해당 유형에서는 그 정도로 큰 N이 주어지는 경우가 드물다고 보셔도 될 것 같습니다! 이전 유형처럼 연결된 정보를 map으로 저장하는 경우, '누가 누구와 저장되었는가'를 저장하기 위한 논리적 지도를 의미하지만, 해당 문제 유형의 map은 실제로 이동이 가능한 물리적 지도를 뜻하기 때문에, '어떤 위치에 0/1이 저장되어 있는가'의 정보를 담고 있어서, 기존 방식처럼 어레이 리스트로 압축하기가 까다롭습니다. 그래서 해당 유형에 대해서는 어레이 리스트 활용을 고민하지 않으셔도 될 것 같습니다! 만약 하셔야 한다면 말씀하신대로 2차원 어레이 리스트를 만들어서 x, y 좌표에 맞게 arrayList를 접근해야 하고, 해당 arrayList는 int 하나가 아닌 다음 방문 가능한 (x,y) 좌표 정보를 묶어서 저장해야될 것 같습니다! (아니면 x * N + y 이런 식으로 한 값을 저장하여 값을 읽을 때 매번 z / N => x, z % N => y 이런식으로 나눠쓰는 방법도 가능하고요)
- 1
- 1
- 36
Q&A
다른 강의 언제나오나용?
안녕하세요 세진님!알고리즘이 재밌어지셨다니... 최고의 칭찬이네요 ㅠ 강의 잘 들어주셔서 정말 감사합니다!다만 제가 요즘 제 나름의 커리어 변화를 시도하고 있어서 강의 제작은 많이 늦어지고 있습니다. ㅠ 마음 같아서는 얼른 만들어서 올려드리겠다고 하고 싶지만, 세진님의 취업을 위해서는 다른 강의를 통해서 배우시는 것이 도움될 것 같습니다.그리디는 어떤 면에서는 단순한데, 알고리즘이라고 하기에는 공통적인 풀이가 존재하지 않아서 약간 어려우실수도 있습니다. 그저 '미래는 생각하지 않고 당장 앞에 놓인 선택에서 최선을 선택한다'라는 태도(?)의 알고리즘이고, 어떤 면에선 우리가 많이 들어온 마시멜로 이야기와 정반대로 눈 앞에 마시멜로가 보이면 당장 먹고, 내일 2개가 보이면 2개를 먹는 것을 선택하는 알고리즘입니다.그래서 문제를 어떻게 정의할지 (어떤 기준으로 정렬하면, 미래를 따지지 않고 당장 눈앞에 놓인 선택만 해도 미래까지 좋은 선택이 될까?)가 핵심이고, 이게 정의되고 나면 구현은 생각보다 정말 간단한 유형입니다.그래서 저는 이 유형은 오래 고민하시기 보다 여러 문제를 풀며 감을 익히는 걸 추천드려요. 시간도 많고 여유롭다면 한 문제를 일주일 동안 고민하시는 게 사고력에 가장 큰 도움이 되지만... 문제 은행식 알고리즘 시험을 대비하기엔 너무 안일한 계획이기도 해서요. 그리디도 여러 문제 풀어보시면 '이래서 정렬을 잘하라 했구나' 감이 오실거에요!이렇게 정리하고 나니 유형별로 문제 뽑아서 얼른 강의 촬영하고 싶어지네요 ㅠ 제 나름의 도전에서 아직 길을 찾고 있는 중이라 조금 더 자리가 잡히면 강의 잘 준비해서 찾아뵙겠습니다. 물론 그땐 꼭 취업하셔서 뵈어요! 공부 화이팅 하세요 세진님 :)
- 1
- 2
- 54
Q&A
백준 13565 침투 질문
안녕하세요 mangmang02211119님 :)좋은 질문 감사합니다! 말씀하신 것처럼, 문제에서 정의된 변수 기준으로 보자면 M이 행 (row), N이 열 (column)이 맞기 때문에, 강의 코드에서 사용한 N과 M의 역할은 문제 기준과 반대입니다.즉, 문제 기준에 맞추려면 M → N, N → M으로 바꿔주는 게 맞습니다.다만, 현재 강의 코드에서는 N을 행 개수로, M을 열 개수로 사용하는 방식으로 일관되게 구현했기 때문에, 변수 이름만 문제와 다를 뿐 실제 동작에는 문제가 없습니다. DFS 탐색 범위나 종료 조건도 이 기준에 맞춰 작성되어 있어서 코드 자체는 정상 작동합니다.결론적으로,✔ 코드 논리에는 문제가 없지만,✔ 문제 설명과 변수 의미를 맞추려면 M과 N의 역할을 바꿔주는 게 맞습니다!제가 이 부분을 틀린지도 모르고 당연히 N, M 이라고 가정하고 작성했네요..!! 정확하게 잡아주셔서 감사합니다 :)
- 1
- 2
- 42
Q&A
침투/섬개수 질문
안녕하세요 정구호님 🙂 입력 형태는 문제에서 주어지는 예제 입력 형태를 보고 설명과 함께 유추할 수 있습니다! 대부분의 경우 이 부분은 헷갈리지 않도록 명확하게 적어주고 있어서, 예제 형태를 그대로 적용하시면 될 것 같습니다! 그리고 다음 추가 질문에 대해 답변 드리자면하나더 질문이 있는데 섬의개수에서for i in range(1,H+1)row = list(map(int,input().split()))이 부분으로 그래프를 채울수 있는거 아닌가요? 이 코드 이후에 것(for j in range(1, M + 1): map_[i][j] = (row[j - 1] == 1))들은 왜 구현한건지 이해가 잘안됩니다row 변수는 한 행에 해당하는 입력 값을 하나의 list로 입력 받은 것이고, 이 정보를 다시 map에 반영하기 위해서는 row list의 값을 확인하여 하나씩 입력해줘야 하기 때문에 이렇게 넣었습니다!
- 1
- 2
- 99
Q&A
노드간 거리 계산
안녕하세요 nurugji님 🙂 말씀하신 대로 대부분의 경우에는 사이클이 없는 구조, 즉 트리 형태에서 주로 사용됩니다. 이 경우, 노드 u와 v 사이의 경로는 유일하기 때문에 count 변수를 이용해 거리를 쉽게 계산할 수 있습니다.그러나 사이클이 존재하는 그래프에서도 몇 가지 추가 처리를 통해 이 방식을 사용할 수 있습니다. 예를 들어:방문 여부(visited 배열)를 관리하여 이미 방문한 노드를 다시 방문하지 않도록 처리하면 사이클을 무시할 수 있습니다.DFS 시작점을 고정하고, 각 노드의 거리를 기준점(루트 또는 특정 노드)으로 계산한 후, 두 노드의 거리를 비교하여 결과를 구할 수 있습니다.하지만 일반적으로 사이클이 있는 그래프에서는 BFS나 다익스트라 알고리즘과 같은 방법이 더 안정적이고 효율적일 수 있습니다.따라서 사이클이 없는 경우에는 설명 드린 방식이 유효하지만, 사이클이 있는 경우에는 위와 같은 추가 처리를 고려해 주시면 더 정확한 결과를 얻을 수 있습니다.혹시 추가로 궁금하신 부분이 있다면 알려주세요! 감사합니다 :)
- 1
- 1
- 98
Q&A
재귀함수 질문
안녕하세요 🙂 우선 두 함수를 더 정확하게 예제로 작성해주시면 질문을 이해하기 더 쉬울 것 같아요. 여기서 베이스 케이스가 정확히 어떤 의미인지 확실하지 않아서 답변 드리기 고민되는데, 현재 이해한 대로 답변 드리고 부족한 부분 있으면 추가 질문 부탁드려요!두 코드의 동작은 동일합니다. Python에서는 명시적으로 return을 작성하지 않아도 함수가 끝나면 암묵적으로 None을 반환하고 종료됩니다. 따라서 두 코드 모두 실행 결과는 동일하며, 동작에 차이는 없습니다. 그러나 코드 작성 의도와 가독성 면에서 약간의 차이가 있습니다.첫 번째 코드에서는 return을 명시하지 않아 함수가 자연스럽게 종료되도록 작성한 것으로, 특별히 함수 종료를 강조하지 않습니다. 이 경우, 단순히 함수의 끝에서 아무 작업도 하지 않고 넘어가는 상황이라면 적합합니다.두 번째 코드에서는 return을 명시적으로 작성하여 함수가 해당 위치에서 종료된다는 것을 분명히 나타냅니다. 이는 베이스 케이스를 명확히 구분하고자 하거나, 함수 종료를 코드 상에서 의도적으로 강조하고 싶을 때 사용합니다. 특히 협업 상황에서 코드의 의도를 명확히 전달하기 위해 유용할 수 있습니다.결론적으로 두 코드의 실행은 같지만, 첫 번째 코드는 단순하고 암시적인 종료를 의도한 경우에 적합하고, 두 번째 코드는 의도를 명확히 표현하고 싶을 때 더 적합합니다. 상황에 따라 적절한 방식을 선택하면 됩니다.
- 1
- 1
- 102