Skip to content
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
90 changes: 90 additions & 0 deletions clone-graph/haxr369.java
Original file line number Diff line number Diff line change
@@ -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<Node> neighbors;

public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}

public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}

public Node(int _val, ArrayList<Node> _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<Node> neighbors = node.neighbors; // 이전 것

List<Node> 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');
}
}
81 changes: 81 additions & 0 deletions longest-repeating-character-replacement/haxr369.java
Original file line number Diff line number Diff line change
@@ -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<Character, Integer> 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<Character, Integer> winState, int winLen) {
int minChng = Integer.MAX_VALUE;
Iterator<Map.Entry<Character, Integer>> it = winState.entrySet().iterator();
// 비어 있다면 0개로 출력
if (!it.hasNext()) {
return 0;
}

// 뭔가 있으면 돌리기
while (it.hasNext()) {
Map.Entry<Character, Integer> entry = it.next();
int v = entry.getValue();
int chng = winLen - v;
minChng = Integer.min(chng, minChng);
}
return minChng;
}
}
127 changes: 127 additions & 0 deletions pacific-atlantic-water-flow/haxr369.java
Original file line number Diff line number Diff line change
@@ -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<List<Integer>> 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<int[]> 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<List<Integer>> ans = new ArrayList<>();

for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
if (flowed[i][j] == 3) {
List<Integer> tmp = new ArrayList<>(Arrays.asList(i, j));
ans.add(tmp);
}
}
}

return ans;

}

private void bfs(Queue<int[]> 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');
}
}
}
45 changes: 45 additions & 0 deletions reverse-bits/haxr369.java
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 원본을 먼저 바이너리 배열로 만들어놓고 역순으로 하는 방법도 있네요ㅎㅎ 👍

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;
}
}