[dahyeong-yun] WEEK 07 Solutions - #2802
Conversation
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
unique-paths/dahyeong-yun.java
/**
* TC : O(min(m, n))
* - m, n 중에 더 작은 수의 -1 을 한 만큼 순회하므로 O(min(m, n))
* SC : O(1)
* - 유의미한 공간 생성이 없음.
*/
class Solution {
public int uniquePaths(int m, int n) {
int selectCount = Math.min(m - 1, n - 1); // 선택할 개수 (r)
int totalCount = m + n - 2; // 선택 가능한 총 개수 (n)
long combination = 1;
for (int i = 1; i <= selectCount; i++) {
combination = combination * (totalCount - selectCount + i) / i;
}
return (int) combination;
}
}- 패턴: Dynamic Programming, Binary Search, Divide and Conquer
- 설명: 주어진 코드는 두 차원의 그리드에서 최단/경로를 조합으로 계산하는 문제의 해법으로, 총 이동 횟수에서 필요한 선택의 경우의 수를 계산하는 조합(Combination) 수식을 이용합니다. 특정 패턴은 조합 계산의 직접 구현으로 DP나 이분 탐색과 같은 일반적 패턴보다 수학적 조합 접근에 가깝지만, 코드에서 보이는 주된 아이디어는 상태의 선택을 최적화된 방식으로 계산하는 것에 있습니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(min(m, n)) | O(min(m, n)) | ✅ |
| Space | O(1) | O(1) | ✅ |
피드백: 팩토리얼 없이 조합을 점진적으로 계산해 공간을 상수로 유지한다.
개선 제안: 현재 구현이 적절해 보입니다.
📊 dahyeong-yun 님의 학습 현황이번 주 제출 문제
누적 학습 요약
문제 풀이 현황
🤖 이 댓글은 GitHub App을 통해 자동으로 작성되었습니다. 🔢 API 사용량 (gpt-5-nano)
|
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
longest-substring-without-repeating-characters/dahyeong-yun.java
/**
* TC : O(n)
* - 문자열 길이 n 만큼 순회하므로 O(n)
* SC : O(min(m, n))
* - map 의 최대 크기는 문자열 길이 n과 알파벳 종류 수 m == 26 중 더 작은 수이므로 O(min(m, n))
*/
class Solution {
public int lengthOfLongestSubstring(String s) {
// "abcabcbb"
// v - cursor = maxLen;
int maxLen = 0;
Map<Character, Integer> map = new HashMap<>();
int anchor = 0;
for(int cursor = 0; cursor < s.length(); cursor++) {
char c = s.charAt(cursor);
if(map.containsKey(c)) {
anchor = Math.max(anchor, map.get(c) + 1);
}
map.put(c, cursor);
maxLen = Math.max(maxLen, cursor - anchor + 1);
}
return maxLen;
}
}- 패턴: Hash Map / Hash Set, Sliding Window, Greedy
- 설명: 해당 코드는 슬라이딩 윈도우로 부분문자열 길이를 구하며, 각 문자 위치를 해시맵으로 관리해 중복을 피해 윈도우의 시작 지점을 조정합니다. 부분해법은 탐욕적으로 현재 최장 구간을 업데이트합니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(n) | O(n) | ✅ |
| Space | O(min(m, n)) | O(min(n, m)) | ❌ |
피드백: 문자 등장 위치를 맵에 저장하고 커서를 따라가며 중복 발생 시 앵커를 갱신합니다. 최댓값은 현재 커서 위치와 앵커 차이로 계산합니다.
개선 제안: 현재 구현이 적절해 보입니다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
number-of-islands/dahyeong-yun.java
/**
* TC : O(m * n)
* - 그리드 원소 갯수 m * n 만큼 순회하므로
* SC : O(m * n)
* - 그리드 원소 갯수 m * n 만큼 재귀 호출이 발생할 수 있으므로
*/
class Solution {
char[][] grid;
int rLen = 0;
int cLen = 0;
public int numIslands(char[][] grid) {
this.grid = grid;
this.rLen = grid.length;
this.cLen = grid[0].length;
int count = 0;
for(int row=0; row<rLen;row++) {
for(int col=0; col<cLen; col++) {
if(grid[row][col] == '1') {
count++;
cover(row, col);
}
}
}
return count;
}
void cover(int row, int col) {
if(row < 0 || col < 0 || row >= this.rLen || col >= this.cLen || this.grid[row][col] != '1') {
return;
}
this.grid[row][col] = '2';
// 좌우상하 다 처리
cover(row + 1, col);
cover(row - 1, col);
cover(row, col + 1);
cover(row, col - 1);
}
} - 패턴: Depth-First Search, Backtracking
- 설명: 그리드에서 섬을 탐색하며 인접한 '1'을 재귀적으로 방문해 분리된 영역을 하나의 섬으로 처리합니다. 재귀를 이용한 DFS 형태로 인접 노드를 순회하는 패턴이 명확합니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(m * n) | O(m * n) | ✅ |
| Space | O(m * n) | O(m * n) | ✅ |
피드백: 그리드의 모든 셀을 한 번씩 방문하고, 1인 셀을 발견하면 DFS로 연속된 1을 2로 바꿔 방문 처리합니다.
개선 제안: 재귀 깊이가 커질 경우 스택 오버플로우 위험이 있으니 비재귀 DFS 또는 BFS로 구현 대안 고려
There was a problem hiding this comment.
오오 회원님은 해당 로직 어떻게 찾아내셨나요?
There was a problem hiding this comment.
길찾기 그림이 어렸을 떄 순열 조합 풀던거랑 비슷한 거 같아서 해봤어요 :) 아래로 가는 화살표와 오른쪽으로 가는 화살표의 조합으로 풀었는데 처음엔 숫자가 너무 커서 오버플로우가 되는 경우가 있더라구요. 그래서 힌트를 좀 얻었는데 연속된 k개의 숫자 곱은 k!로 나누어 떨어지기 때문에 매 루프마다 나누는 식으로 오버플로우를 없애는 식으로 풀어봤습니다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
reverse-linked-list/dahyeong-yun.java
/**
* TC : O(n)
* - 전체 리스트를 한번 순회 하므로 O(n)
* SC : O(1)
* - 임시 변수 하나만 사용하므로 O(1)
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
while(head != null) {
ListNode next = head.next; // 다음 순서의 노드
head.next = prev; // 현재 노드의 다음을 이전 노드로
prev = head; // 다음 차례의 이전 노드는 현재
head = next; // 다음 차례는 임시 저장했던 노느
}
return prev;
}
}- 패턴: Two Pointers, Linked List
- 설명: 주어진 코드는 연결 리스트를 한 번 순회하며 포인터를 앞 노드로 이동시키는 방식으로 역순으로 뒤집습니다. 두 포인터를 사용한 순회 구조와 연결 리스트의 노드 포인터 재배치가 핵심 패턴입니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(n) | O(n) | ✅ |
| Space | O(1) | O(1) | ✅ |
피드백: 순회 중 현재 노드를 가리키는 포인터를 유지하며 포인터 연결을 뒤바꾸는 일반적인 역순화 방법이다.
개선 제안: 현재 구현이 적절해 보입니다.
parkhojeong
left a comment
There was a problem hiding this comment.
수고하셨습니다. 사소한 커멘트 몇 개 남겼습니다.
| void cover(int row, int col) { | ||
| if(row < 0 || col < 0 || row >= this.rLen || col >= this.cLen || this.grid[row][col] != '1') { | ||
| return; | ||
| } | ||
|
|
||
| this.grid[row][col] = '2'; | ||
|
|
||
| // 좌우상하 다 처리 | ||
| cover(row + 1, col); | ||
| cover(row - 1, col); | ||
| cover(row, col + 1); | ||
| cover(row, col - 1); |
There was a problem hiding this comment.
재귀 깊이가 최대 m x n 까지 가능해서 재귀를 사용하지 않고 풀어보시면 좋을 거 같습니다.
| count++; | ||
| cover(row, col); | ||
| } |
There was a problem hiding this comment.
cover라는 함수명이 무엇을 하는지 드러나는 거 같지는 않아서 의미가 드러나도록 바꿔주면 좋을 거 같습니다.
| class Solution { | ||
| public int uniquePaths(int m, int n) { | ||
| int selectCount = Math.min(m - 1, n - 1); // 선택할 개수 (r) | ||
| int totalCount = m + n - 2; // 선택 가능한 총 개수 (n) |
There was a problem hiding this comment.
주석에 있는 n과 변수의 n 이 같은 단어인데 다른 의미로 쓰이는 거 같습니다.
| class Solution { | ||
| public int uniquePaths(int m, int n) { | ||
| int selectCount = Math.min(m - 1, n - 1); // 선택할 개수 (r) | ||
| int totalCount = m + n - 2; // 선택 가능한 총 개수 (n) | ||
|
|
||
| long combination = 1; | ||
| for (int i = 1; i <= selectCount; i++) { | ||
| combination = combination * (totalCount - selectCount + i) / i; | ||
| } | ||
|
|
||
| return (int) combination; |
There was a problem hiding this comment.
어떤 의도로 푸셨는지 코드로 많이 드러나있던 거 같습니다. 덕분에 비교적 쉽게 이해할 수 있었던 거 같아요.
답안 제출 문제
작성자 체크 리스트
In Review로 설정해주세요.검토자 체크 리스트
Important
본인 답안 제출 뿐만 아니라 다른 분 PR 하나 이상을 반드시 검토를 해주셔야 합니다!