diff --git a/clone-graph/haxr369.java b/clone-graph/haxr369.java new file mode 100644 index 0000000000..0416fee146 --- /dev/null +++ b/clone-graph/haxr369.java @@ -0,0 +1,90 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * Runtime: 25 ms (Beats 72.12%) + * Memory: 44.35 MB (Beats 34.32%) + * Space Complexity: O(N) + * - 모든 노드 저장 => O(N) + * - visited로 복사했던 노드 관리 => O(N) + * > O(N) + * Time Complexity: O(N) + * - 루트노드부터 모든 노드까지 한번씩 탐색 => O(N) + * > O(N) + * + */ + +class Node { + public int val; + public List neighbors; + + public Node() { + val = 0; + neighbors = new ArrayList(); + } + + public Node(int _val) { + val = _val; + neighbors = new ArrayList(); + } + + public Node(int _val, ArrayList _neighbors) { + val = _val; + neighbors = _neighbors; + } +} + +class Solution { + public Node cloneGraph(Node node) { + if (node == null) { + return node; + } + + if (node.neighbors == null) { + Node newNode = new Node(node.val, null); + return newNode; + } else if (node.neighbors.isEmpty()) { + Node newNode = new Node(node.val, new ArrayList<>()); + return newNode; + } + + Node[] visited = new Node[104]; + + Node ans = new Node(node.val, new ArrayList<>(node.neighbors)); + visited[ans.val] = ans; + dfs(ans, visited); + + return ans; + } + + /** + * node의 리스트를 dfs로 변경해간다. + * 다만, 변경했던 노드는 다시 변경하지 않음 + */ + private void dfs(Node node, Node[] visited) { + + List neighbors = node.neighbors; // 이전 것 + + List newNeighbors = new ArrayList<>(); // 새 껍질 + // 하나씩 새걸로 바꾸자 + for (Node n : neighbors) { + if (visited[n.val] != null) { + newNeighbors.add(visited[n.val]); + continue; + } + Node newN = new Node(n.val, new ArrayList<>(n.neighbors)); // 껍질 만들기 + visited[newN.val] = newN; + dfs(newN, visited); // + newNeighbors.add(newN); + } + node.neighbors = newNeighbors; // 신규 리스트로 바꿔치기 + // printNode(node); + } + + private void printNode(Node node) { + System.out.print("val -> " + node.val); + System.out.println(" size -> " + node.neighbors.size()); + node.neighbors.forEach(n -> System.out.print(n.val)); + System.out.print('\n'); + } +} diff --git a/longest-repeating-character-replacement/haxr369.java b/longest-repeating-character-replacement/haxr369.java new file mode 100644 index 0000000000..2c2ff27426 --- /dev/null +++ b/longest-repeating-character-replacement/haxr369.java @@ -0,0 +1,81 @@ +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Runtime: 105 ms (Beats 5.05%) + * Memory: 46.94 MB (Beats 25.55%) + * Space Complexity: O(1) + * > 26개 영문자에 대한 Hash 테이블 => O(26) => O(1) + * Time Complexity: O(N) + * - 윈도우를 문자열 길이만큼 이동시키기 => O(N) + * - 윈도우 변경할 때마다 최소변경필요개수 구하기 => O(26) => O(1) + * > O(N)xO(1) => O(N) + * + */ +class Solution { + /** + * 슬라이딩 윈도우 기법 사용 + * + * 1. 시작인덱스, 종료인덱스 설정. + * 2. 윈도우 안에 변경 필요 건수가 k 보다 크면 시작인덱스 늘리기 => 변환할 수 없기 때문에 + * 3. 만약 변경 필요 건수가 k와 작거나 같다면 종료인덱스 늘리기 => 변환 가능한 유효한 문자열이기 때문 + */ + public int characterReplacement(String s, int k) { + int strIdx = 0; + int endIdx = 0; + int visited = -1; // visited 문자까지는 윈도우에 들어갔기 때문에 넣지 않는다. + int ans = 0; + + // 윈도우 상태 관리 + Map winState = new HashMap<>(); + + while (s.length() > endIdx) { + + // endC를 윈도우에 추가하기 + if (visited < endIdx) { // 두번 넣지 않게 방어막 쳐주기 + Character endC = Character.valueOf(s.charAt(endIdx)); + int temp = winState.getOrDefault(endC, 0); + winState.put(endC, temp + 1); + visited++; + } + + // 유효성 검사하기 O(26) + int minChng = cntMinChng(winState, endIdx - strIdx + 1); + if (minChng <= k) { // 유효한 상태 + ans = Integer.max(ans, endIdx - strIdx + 1); + endIdx++; + } else { // 유효하지 않은 상태 + Character strC = Character.valueOf(s.charAt(strIdx)); + // 뒷자리 하나 빼기 + int temp = winState.getOrDefault(strC, 0); + winState.put(strC, temp - 1); + strIdx++; + } + } + return ans; + } + + /** + * 시간복잡도 => O(26) + * 윈도우에서 최소변경필요개수 카운트 + * 변경해야할 최소 값 = 현재 윈도우 길이 - (가장 많이 등장한 문자 개수) + */ + private int cntMinChng(Map winState, int winLen) { + int minChng = Integer.MAX_VALUE; + Iterator> it = winState.entrySet().iterator(); + // 비어 있다면 0개로 출력 + if (!it.hasNext()) { + return 0; + } + + // 뭔가 있으면 돌리기 + while (it.hasNext()) { + Map.Entry entry = it.next(); + int v = entry.getValue(); + int chng = winLen - v; + minChng = Integer.min(chng, minChng); + } + return minChng; + } +} diff --git a/pacific-atlantic-water-flow/haxr369.java b/pacific-atlantic-water-flow/haxr369.java new file mode 100644 index 0000000000..065ac728bf --- /dev/null +++ b/pacific-atlantic-water-flow/haxr369.java @@ -0,0 +1,127 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +class Solution { + + private final int[] dy = { -1, 1, 0, 0 }; + private final int[] dx = { 0, 0, -1, 1 }; + private int M = 0, N = 0; + + /** + * 특정 노드에서 시작에서 이웃 노드를 거쳐 두 바다로 갈 수 있는 노드 리스트를 출력하기 + * 특정 노드에서 전체 탐색? => O(NxM) x O(NxM) 탐색 필요. + * + * 그럼 태평양, 대서양 각각에서 도달할 수 있는 노드 리스트 찾기(본인 이상 값을 가진 노드로 탐색) + * 그리고 겹치는 지점 찾기 => 답 + * 3xO(NxM) + * + * Runtime: 11 ms (Beats 28.23%) + * Memory: 46.9 MB (Beats 98.39%) + * Space Complexity: O(NxM) + * - 노드 방문 여부를 체크하기 위한 flowed O(NxM) + * - 방문하는 노드를 큐에 찾기 qu O(NxM) + * > 2O(NxM) => O(NxM) + * Time Complexity: O(NxM) + * - 태평양 인접 노드 탐색 O(NxM) + * - 대서양 인접 노드 탐색 O(NxM) + * - 두 대양 인접 노드 검색 O(NxM) + * > 3O(NxM) + */ + public List> pacificAtlantic(int[][] heights) { + M = heights.length; + N = heights[0].length; + int[][] flowed = new int[M][N]; // 1이면 태평양 인접, 2면 대서양, 3이면 둘 다, 0이면 인접X + + // (0,0) ~ (0,N-1)을 1로 넣고 bfs 돌리기 + Queue qu = new LinkedList<>(); + for (int i = 0; i < N; i++) { + int[] temp = { 0, i }; + flowed[0][i] += 1; + qu.add(temp); + } + // (1, 0) ~ (M-1, 0) + for (int i = 1; i < M; i++) { + int[] temp = { i, 0 }; + flowed[i][0] += 1; + qu.add(temp); + } + // 태평양 탐색 + bfs(qu, flowed, heights, 1); + + // printMp(flowed); + + // System.out.println("------------"); + + qu = new LinkedList<>(); + // (M-1, 0) ~ (M-1, N-1) + for (int i = 0; i < N; i++) { + int[] temp = { M - 1, i }; + flowed[M - 1][i] += 2; + qu.add(temp); + } + // (0, 0) ~ (M-2, N-1) + for (int i = 0; i < M - 1; i++) { + int[] temp = { i, N - 1 }; + flowed[i][N - 1] += 2; + qu.add(temp); + } + // 태평양 탐색 + bfs(qu, flowed, heights, 2); + List> ans = new ArrayList<>(); + + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + if (flowed[i][j] == 3) { + List tmp = new ArrayList<>(Arrays.asList(i, j)); + ans.add(tmp); + } + } + } + + return ans; + + } + + private void bfs(Queue qu, int[][] flowed, int[][] heights, int oceanTp) { + while (!qu.isEmpty()) { + int[] node = qu.poll(); + int h = heights[node[0]][node[1]]; + + // 사방을 보면서 적절한 노드를 큐에 넣기 + for (int n = 0; n < 4; n++) { + int ny = node[0] + dy[n]; + int nx = node[1] + dx[n]; + + // 섬 밖 위치인지 체크 + if (ny < 0 || ny >= M || nx < 0 || nx >= N) { + continue; + } + // 방문했던 위치면 넘어가기 + if (flowed[ny][nx] >= oceanTp) { + continue; + } + // 바다에서 섬으로 갈 수 있는 방향인지 체크 + if (h > heights[ny][nx]) { + continue; + } + flowed[ny][nx] += oceanTp; + int[] temp = { ny, nx }; + qu.add(temp); + } + } + } + + private void printMp(int[][] mp) { + int my = mp.length; + int mx = mp[0].length; + for (int y = 0; y < my; y++) { + for (int x = 0; x < mx; x++) { + System.out.print(mp[y][x] + " "); + } + System.out.print('\n'); + } + } +} diff --git a/reverse-bits/haxr369.java b/reverse-bits/haxr369.java new file mode 100644 index 0000000000..3bed7170df --- /dev/null +++ b/reverse-bits/haxr369.java @@ -0,0 +1,45 @@ +class Solution { + /** + * Runtime: 1 ms (Beats 54.22%) + * Memory: 42.34 MB (Beats 63.68%) + * Space Complexity: O(1) + * > 고정된 32byte 배열 사용으로 O(1) + * Time Complexity: O(logN) + * - n의 2진수 변환 => O(logN) + * - 32bit 역순 변환 => O(1) + * > O(log32) + O(1) => O(log32) 사실상 O(1) + * + */ + public int reverseBits(int n) { + byte[] binarys = new byte[32]; + int temp = n; + + // n의 2진수를 저장하기 + int i = 0; + while (temp > 0) { // 최종 0이되면 종료 + // 짝수인 경우 i번째 비트는 0 + if (temp % 2 == 0) { + binarys[i] = 0; + } else { // 홀수면 i번째 비트는 1 + binarys[i] = 1; + temp -= 1; + } + temp = temp / 2; + i++; // 비트수 올리기 + } + + // 저장된 비트를 역순으로 십진수로 변환하기 + int ans = 0; // 총합산 + int base = 1; // i-j번째 2진수 값 + int j = 0; + while (31 >= j) { + // 2진수가 1인 경우만 합산한다. + if (binarys[31 - j] == 1) { + ans += base; + } + base *= 2; + j++; + } + return ans; + } +}