diff --git a/clone-graph/jinvicky.java b/clone-graph/jinvicky.java new file mode 100644 index 000000000..26d608883 --- /dev/null +++ b/clone-graph/jinvicky.java @@ -0,0 +1,26 @@ +import java.util.HashMap; +import java.util.Map; + +class Solution { + public Node cloneGraph(Node node) { + if (node == null) return null; + + Map map = new HashMap<>(); + return clone(node, map); + } + + private Node clone(Node node, Map map) { + if (map.containsKey(node)) { + return map.get(node); + } + + Node clonedNode = new Node(node.val); + map.put(node, clonedNode); + + for (Node neighbor : node.neighbors) { + clonedNode.neighbors.add(clone(neighbor, map)); + } + + return clonedNode; + } +} diff --git a/invert-binary-tree/jinvicky.java b/invert-binary-tree/jinvicky.java new file mode 100644 index 000000000..c25d9f847 --- /dev/null +++ b/invert-binary-tree/jinvicky.java @@ -0,0 +1,76 @@ +import java.util.LinkedList; +import java.util.Queue; + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + public TreeNode invertTree(TreeNode root) { + if (root == null) return null; + + TreeNode temp = root.left; + root.left = root.right; + root.right = temp; + + System.out.println(root.val); + + invertTree(root.left); + invertTree(root.right); + + return root; + } + + public TreeNode invertTreeByQueue(TreeNode root) { + if (root == null) { + return null; + } + + // BFS를 위한 큐 생성 + Queue queue = new LinkedList<>(); + queue.add(root); + + // 큐가 빌 때까지 반복 + while (!queue.isEmpty()) { + TreeNode current = queue.poll(); + + // 현재 노드의 왼쪽 자식과 오른쪽 자식 교환 + TreeNode temp = current.left; + current.left = current.right; + current.right = temp; + + // 자식 노드가 있으면 큐에 추가 + if (current.left != null) { + queue.add(current.left); + } + if (current.right != null) { + queue.add(current.right); + } + } + + return root; + } +} +/** + * public TreeNode invertTreeByQueue(TreeNode root) { + * // root가 널이면 리턴 + * // 큐 선언하고 루트를 삽입 + * + * // 큐가 비기 전까지 연산 반복 + * // temp 변수로 left와 right을 교체 + * // 자식 left 노드를 큐에 추가 (있다면) + * // 자식 right 노드를 큐에 추가 (있다면) + * // 루트를 반환 + * } + */ diff --git a/longest-common-subsequence/jinvicky.java b/longest-common-subsequence/jinvicky.java index 57a5da484..9659fbcea 100644 --- a/longest-common-subsequence/jinvicky.java +++ b/longest-common-subsequence/jinvicky.java @@ -1,5 +1,8 @@ class Solution { + // dp 표를 봐야 이해가 더 쉽다. https://twinw.tistory.com/126 + // dp, 즉 메모이제이션의 범위는 이전 row인 것이다. (기존 cell 위주의 문제보다 넓은 범위) public int longestCommonSubsequence(String text1, String text2) { + // 왼쪽과 위로 1줄씩 버퍼(여유) 배열이 있다. 즉, dp[0][..], dp[..][0]은 0으로 초기화된 상태 int m = text1.length(); int n = text2.length(); diff --git a/longest-repeating-character-replacement/jinvicky.java b/longest-repeating-character-replacement/jinvicky.java new file mode 100644 index 000000000..5e624fbf0 --- /dev/null +++ b/longest-repeating-character-replacement/jinvicky.java @@ -0,0 +1,51 @@ +import java.util.HashMap; +import java.util.Map; + +class Solution { + public int characterReplacement(String s, int k) { + Map charCount = new HashMap<>(); + + int left = 0; + int maxFrequency = 0; + int maxLength = 0; + + for(int right = 0; right < s.length(); right++) { + char rightChar = s.charAt(right); + + charCount.put(rightChar, charCount.getOrDefault(rightChar, 0) + 1); + + maxFrequency = Math.max(maxFrequency, charCount.get(rightChar)); + + if((right - left + 1) - maxFrequency > k) { + char leftChar = s.charAt(left); + + charCount.put(leftChar, charCount.get(leftChar) - 1); + left++; + } + + maxLength = Math.max(maxLength, right - left + 1); + } + return maxLength; + } + + // while문과 배열로 성능이 개선된 풀이 + public int characterReplacement2(String s, int k) { + int left = 0, right = 0; + int maxCount = 0, result = 0; + int[] freq = new int[26]; + + while (right < s.length()) { + freq[s.charAt(right) - 'A']++; + maxCount = Math.max(maxCount, freq[s.charAt(right) - 'A']); + + while ((right - left + 1) - maxCount > k) { + freq[s.charAt(left) - 'A']--; + left++; + } + + result = Math.max(result, right - left + 1); + right++; + } + return result; + } +} diff --git a/maximum-product-subarray/jinvicky.java b/maximum-product-subarray/jinvicky.java index 523554013..75099c485 100644 --- a/maximum-product-subarray/jinvicky.java +++ b/maximum-product-subarray/jinvicky.java @@ -1,4 +1,5 @@ class Solution { + // 최소값은 음수가 곱해질 때 최대값이 될 수 있기 때문에 최소, 최대를 각각 dp[]로 관리해야 한다. public int maxProduct(int[] nums) { if (nums.length == 1) return nums[0]; @@ -15,6 +16,11 @@ public int maxProduct(int[] nums) { for (int i = 1; i < len; i++) { // 후보 3을 준비 + /** + * 현재 인덱스값 (justNum) + * 이전 인덱스 최소값 x 현재 인덱스 값 (reverse) + * 이전 인덱스 최대값 x 현재 인덱스 값 (keep) + */ int justNum = nums[i]; // 계속 더한 값 int keep = justNum * max[i-1]; diff --git a/pacific-atlantic-water-flow/jinvicky.java b/pacific-atlantic-water-flow/jinvicky.java new file mode 100644 index 000000000..1a75aba8e --- /dev/null +++ b/pacific-atlantic-water-flow/jinvicky.java @@ -0,0 +1,66 @@ +import java.util.ArrayList; +import java.util.List; + +class Solution { + private int[][] heights; + private int rows, cols; + private int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // 상하좌우 + + public List> pacificAtlantic(int[][] heights) { + this.heights = heights; + this.rows = heights.length; + this.cols = heights[0].length; + + // 태평양과 대서양에서 도달 가능한 지점을 저장하는 배열 + boolean[][] pacific = new boolean[rows][cols]; + boolean[][] atlantic = new boolean[rows][cols]; + + // 태평양과 대서양 경계에서 탐색 시작 + // 맨 윗줄과 맨 아랫줄 + for (int j = 0; j < cols; j++) { + dfs(0, j, pacific, Integer.MIN_VALUE); // 태평양 (윗줄) + dfs(rows - 1, j, atlantic, Integer.MIN_VALUE); // 대서양 (아랫줄) + } + + // 맨 왼쪽줄과 맨 오른쪽줄 + for (int i = 0; i < rows; i++) { + dfs(i, 0, pacific, Integer.MIN_VALUE); // 태평양 (왼쪽줄) + dfs(i, cols - 1, atlantic, Integer.MIN_VALUE); // 대서양 (오른쪽줄) + } + + // 결과를 저장할 리스트 + List> result = new ArrayList<>(); + + // 양쪽 바다로 모두 흐를 수 있는 지점 찾기 + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (pacific[i][j] && atlantic[i][j]) { + List coord = new ArrayList<>(); + coord.add(i); + coord.add(j); + result.add(coord); + } + } + } + + return result; + } + + // 깊이 우선 탐색 (DFS) 함수 + private void dfs(int r, int c, boolean[][] visited, int prevHeight) { + // 유효하지 않은 지점 (범위 밖, 이미 방문, 높이 조건 불만족) + if (r < 0 || r >= rows || c < 0 || c >= cols || visited[r][c] || heights[r][c] < prevHeight) { + return; + } + + // 현재 지점 방문 표시 + visited[r][c] = true; + + // 상하좌우로 탐색 진행 + for (int[] dir : directions) { + int newR = r + dir[0]; + int newC = c + dir[1]; + dfs(newR, newC, visited, heights[r][c]); + } + } +} diff --git a/palindromic-substrings/jinvicky.java b/palindromic-substrings/jinvicky.java new file mode 100644 index 000000000..3f559a9f7 --- /dev/null +++ b/palindromic-substrings/jinvicky.java @@ -0,0 +1,61 @@ + + +class Solution { + + public int countSubstrings(String s) { + int n = s.length(); + int count = 0; + + // 홀수와 짝수 통합 처리 (0부터 2n-1까지) + for (int center = 0; center < 2 * n - 1; center++) { + int left = center / 2; + int right = left + center % 2; + + while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) { + count++; + left--; + right++; + } + } + + return count; + } + + // 더 가독성이 좋은 풀이 + + /** + * 1. 회문의 중심을 명확하게 분리한다. + * 2. c는 회문의 중심후보가 된다. 1글자짜리 중심이거나 혹은 두 글자짜리 회문의 왼쪽 중심이다. + * 3. c를 홀수 길이 회문의 중심으로 설정한다 -> expand(s,c,c) + * 4. c부터 c+1까지 짝수 길이 회문의 왼쪽 중심으로 설정한다 -> expand(s,c,c+1) + *

+ * 이렇게 하는 이유는 ABA와 ABBA 두 가지 경우를 모두 커버하기 위해서이다. + */ + public int countSubstrings2(String s) { + int n = s.length(); + int count = 0; + for (int c = 0; c < n; c++) { + count += expand(s, c, c); // 홀수 길이 중심 + count += expand(s, c, c + 1); // 짝수 길이 중심 + } + return count; + } + + private int expand(String s, int L, int R) { + int add = 0; + while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) { + add++; + L--; + R++; + } + return add; + } + + /** + * 프라이빗 메서드 "확장" 선언 + * 1. L, R 포인터 인덱스를 받는다. + * 2. 두 포인터가 문자열 내 유효한 범위에 있어야 한다. + * 3. L과 R이 가리키는 문자가 같아야 한다. + * 2와 3을 모두 만족한다면 회문 + */ +} diff --git a/reverse-bits/jinvicky.java b/reverse-bits/jinvicky.java new file mode 100644 index 000000000..cb30a2c9a --- /dev/null +++ b/reverse-bits/jinvicky.java @@ -0,0 +1,18 @@ + + +public class Solution { + public int reverseBits(int n) { + int reversed = 0; + + for (int i = 0; i < 32; i++) { + reversed <<= 1; + + int lsb_of_n = n & 1; // n이 홀수면 1, 짝수면 0을 반환 + + reversed |= lsb_of_n; + + n >>= 1; + } + return reversed; + } +} \ No newline at end of file diff --git a/sum-of-two-integers/jinvicky.java b/sum-of-two-integers/jinvicky.java new file mode 100644 index 000000000..7ac79747c --- /dev/null +++ b/sum-of-two-integers/jinvicky.java @@ -0,0 +1,21 @@ +class Solution { + public int getSum(int a, int b) { + + while (b != 0) { + + // 변수 2개와 비트 연산 + // 1. + int sum = a ^ b; + + // 2. + int carry = (a & b) << 1; + + /// 3. + a = sum; + b = carry; // 한번하고 말면 b는 쓰일 일이 없는데? -> 빠뜨린 반복문이 없는지 확인한다. + + } + + return a; + } +}