Skip to content

[jinvicky] WEEK 04 Solutions #1815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions coin-change/jinvicky.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import java.util.Arrays;

class Solution {
public int coinChange(int[] coins, int amount) {
int max=amount+1;
int [] dp=new int[amount+1];
Arrays.fill(dp,max);
dp[0]=0;
for(int coin:coins){
for(int j=coin;j<=amount;j++){ // coin부터 시작해서 일반 루프보다 성능 향상
dp[j]=Math.min(dp[j],dp[j-coin]+1);
}
}
return dp[amount]>amount ? -1:dp[amount];
}
}
31 changes: 31 additions & 0 deletions find-minimum-in-rotated-sorted-array/jinvicky.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;

// 0번째값이 length-1번재 값보다 작다면 rotate되지 않았음을 보장합니다.
// 2,3,4,5,1 0번째 > length-1번째
// 3,4,5,1,2 0번째 > length-1번째
// 1,2,3,4,5 0번째 < length-1번째
if (nums[right] >= nums[left]) return nums[0];

while (left < right) {
// 단순히 (left+right)/2 보다 범위 계산 오차가 없습니다.
int mid = left + (right - left) / 2;

// 중간값이 오른쪽값보다 크다면 왼쪽 포인터를 중간값+1로 증가합니다.
if (nums[mid] > nums[right]) { // <= 와 동일
left = mid + 1;
} else {
// 중간값보다 오른쪽값이 크다면 중간값이 최대 범위가 되어야 합니다.
// 최소값이 mid일 가능성이 있기 때문이다.
right = mid;
}
}
return nums[left];
}
}

// 처음에는 전형 이진 탐색으로서 left = mid+1, right = mid-1을 했으나 실패
// 하지만 최소 숫자는 무조건 left가 가리키는 값임.
22 changes: 22 additions & 0 deletions maximum-depth-of-binary-tree/jinvicky.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 왼쪽 서브트리를 모두 탐색한 다음 오른쪽 서브트리 탐색을 시작
// 1 (root)
// / \
// 2 3
// / \ / \
// 4 5 6 7
//
// root를 인자로 받아서 노드별로 left, right을 또 재귀로 호출하니
// (1)의 left, right, (2)의 left, right, (3)의 left, right, (4)의 left, right이 실행된다.
// 결과적으로 왼쪽 서브트리의 최대 depth와 오른쪽 서브트리의 최대 depth + 최초 root의 depth 1을 합해서 완성
// Math.max()는 함수 안의 모든 값이 계산되어야만 실행된다.
class Solution {
// 최대 깊이를 탐색하는 것이므로 BFS보다 DFS가 더 적절합니다.
// 매 노드의 left, right을 재귀로 호출해서 최대 깊이를 반환합니다. 재귀 함수 필요.
public int maxDepth(TreeNode root) {
// 재귀 종료 조건 == left 혹은 right가 null일 때, root 자체가 널이라면?
if (root == null) return 0;

// 누적을 위해서 1+를 하고, Math.max()로 최댓값을 구합니다.
return 1+ Math.max(maxDepth(root.left), maxDepth(root.right));
}
}
32 changes: 32 additions & 0 deletions merge-two-sorted-lists/jinvicky.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode answer = new ListNode();
ListNode mergePointer = answer;
// 머지를 수행할 포인터와 정답을 반환할 포인터 총 2개의 포인터가 필요합니다.
// 초기화에서 정답 포인터와 머지 포인터가 같은 노드 주소를 바라보게 해야 합니다.
// 머지 포인터가 연산을 계속하더라도 정답 포인터의 next는 정렬된 첫번째 노드를 가리킬 것입니다.
// 머지 포인터는 연산을 계속하면서 참조 주소가 변경되기 때문에 그 자체로 반환하면 안됩니다.

while (list1 != null && list2 != null) {
// list1의 값이 list2의 값보다 작거나 같으면 list1의 노드를 병합
if (list1.val <= list2.val) { // wrong: 값이 더 작거나, 또는 값이 동일할 경우 list1을 우선시해야 합니다.
mergePointer.next = list1;
list1 = list1.next;
} else {
// 그렇지 않으면 list2의 노드를 병합
mergePointer.next = list2;
list2 = list2.next;
}
mergePointer = mergePointer.next;
}

// 두 리스트는 오름차순 정렬을 전제로 하기 때문에 한 리스트의 길이 끝에 도달하면 나머지는 그저 통 붙여넣기를 합니다.
// 두 리스트 중에서 null이 아닌 리스트 노드로 머지 포인터의 next에 연결합니다.
if (list1 != null) {
mergePointer.next = list1;
} else {
mergePointer.next = list2;
}
return answer.next;
}
}
82 changes: 82 additions & 0 deletions word-search/jinvicky.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
class Solution {
public boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(dfs(board, i, j, word, 0)) {
return true;
}
}
}
return false;
}

boolean dfs(char[][] board,int i,int j,String word,int index){
if(index == word.length()) return true;
if(i<0 || j<0 || i>=board.length || j>=board[0].length) return false; // 범위를 벗어난 경우
if(board[i][j] != word.charAt(index)) return false; // 일치 조건을 불만족하는 경우

char temp = board[i][j];
board[i][j] = '#';
boolean found = dfs(board, i+1, j, word, index+1)
|| dfs(board, i-1, j, word, index+1)
|| dfs(board, i, j+1, word, index+1)
|| dfs(board, i, j-1, word, index+1);

board[i][j] = temp;
return found;
}

// 2차원 방문 배열을 만들고 direction 방향 템플릿으로 풀이
public boolean exist2(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
boolean[][] visited = new boolean[m][n];
boolean result = false;

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == word.charAt(0)) {
result = backtrack(board, word, visited, i, j, 0);
if (result)
return true;
}
}
}

return false;
}

private boolean backtrack(char[][] board, String word, boolean[][] visited, int i, int j, int index) {
if (index == word.length()) {
return true;
}

// dfs를 풀 때는 배열 범위를 벗어나는 경우 break를 꼭 기억하기
if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || visited[i][j]
|| board[i][j] != word.charAt(index)) {
return false;
}

visited[i][j] = true;

// if문에서 작성하는 것이 눈에 안 익어서
// direction 템플릿을 만들어서 for문으로 해결하는 암기법으로 변환
int[][] directions = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } }; // 그냥 암기

for (int[] dir : directions) {
// i가 y, j가 x인데 사실 1, -1, 0만 잘 설정하면 상관없음. 목적은 1, -1 1번씩 그리고 나머지는 0으로 채우는 것
int nextI = i + dir[0];
int nextJ = j + dir[1];

if (backtrack(board, word, visited, nextI, nextJ, index + 1)) {
return true;
}
}

visited[i][j] = false;
return false;
}

}