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
59 changes: 59 additions & 0 deletions clone-graph/sangbeenmoon.java

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

clone-graph/sangbeenmoon.java
// Definition for a Node.

import java.util.ArrayList;
import java.util.Map;

/* 
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 Map<Node,Node> map = new HashMap<>();

    public Node cloneGraph(Node node) {
    
      if (node == null) {
        return null;
      }

      return dfs(node);
    }

    public Node dfs(Node origin) {
        if (map.containsKey(origin)) {
            return map.get(origin);
        }

        if (origin == null) {
            return null;
        }

        Node copied = new Node(origin.val);
        map.put(origin, copied);
        
        for (Node n : origin.neighbors) {
            Node neighbor = dfs(n);
            copied.neighbors.add(neighbor);
        }

        return copied;
    }
}
  • 패턴: Depth-First Search, Hash Map / Hash Set
  • 설명: 그래프를 깊이 우선으로 순회하며 각 노드를 복제하고, 원래 노드와 복제본 간 매핑을 HashMap으로 저장하여 이미 방문한 노드를 재사용합니다. 순회 시 재귀dfs로 이웃 노드를 방문하며 연결 관계를 재현합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(N + E)
Space O(N)

피드백: 맵으로 원본 노드와 복제본 노드를 매핑해 사이클이 있는 그래프에서도 중복 복제를 방지한다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

// Definition for a Node.

import java.util.ArrayList;
import java.util.Map;

/*
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 Map<Node,Node> map = new HashMap<>();

public Node cloneGraph(Node node) {

if (node == null) {
return null;
}

return dfs(node);
}

public Node dfs(Node origin) {
if (map.containsKey(origin)) {
return map.get(origin);
}

if (origin == null) {
return null;
}

Node copied = new Node(origin.val);
map.put(origin, copied);

for (Node n : origin.neighbors) {
Node neighbor = dfs(n);
copied.neighbors.add(neighbor);
}

return copied;
}
}
33 changes: 33 additions & 0 deletions longest-common-subsequence/sangbeenmoon.java

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

longest-common-subsequence/sangbeenmoon.java
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {

        int dp[][] = new int[text1.length()][text2.length()];


        for(int i = 0; i < text1.length(); i++){
            if (text1.substring(0,i + 1).contains(String.valueOf(text2.charAt(0)))) {
                dp[i][0] = 1;
            }
        }

        for(int i = 0; i < text2.length(); i++){
            if (text2.substring(0,i + 1).contains(String.valueOf(text1.charAt(0)))) {
                dp[0][i] = 1;
            }
        }

        for(int i = 1; i < text1.length(); i++){
            for(int j = 1; j< text2.length(); j++){
                if(text1.charAt(i) == text2.charAt(j)){
                    dp[i][j] = dp[i-1][j-1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        
        return dp[text1.length() - 1][text2.length() - 1];
        

    }
}
  • 패턴: Dynamic Programming
  • 설명: 두 문자열의 최장 공통 부분 수열을 구하기 위해 이차원 DP 테이블을 채우는 방식으로 문제를 해결합니다. 이전 상태의 값을 이용해 현재 상태를 구성하는 전형적인 DP 패턴입니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n * m)
Space O(n * m)

피드백: 2차원 DP 배열을 사용해 모든 부분문제 결과를 저장한다.

개선 제안: 경계 초기화와 인덱스 접근을 명확히 하고, 공간을 줄이려면 한 행만 사용하는 방법도 있다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class Solution {
public int longestCommonSubsequence(String text1, String text2) {

int dp[][] = new int[text1.length()][text2.length()];


for(int i = 0; i < text1.length(); i++){
if (text1.substring(0,i + 1).contains(String.valueOf(text2.charAt(0)))) {
dp[i][0] = 1;
}
}

for(int i = 0; i < text2.length(); i++){
if (text2.substring(0,i + 1).contains(String.valueOf(text1.charAt(0)))) {
dp[0][i] = 1;
}
}

for(int i = 1; i < text1.length(); i++){
for(int j = 1; j< text2.length(); j++){
if(text1.charAt(i) == text2.charAt(j)){
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}

return dp[text1.length() - 1][text2.length() - 1];


}
}
46 changes: 46 additions & 0 deletions longest-repeating-character-replacement/sangbeenmoon.java

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

longest-repeating-character-replacement/sangbeenmoon.java
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

class Solution {

    Map<Character, Integer> counterMap = new HashMap<>();

    public int characterReplacement(String s, int k) {
        
        int left = 0;
        int answer = 0;

        for (int right = 0; right < s.length(); right++){  
            if(counterMap.containsKey(s.charAt(right))){
           
                int cnt = counterMap.get(s.charAt(right));
                counterMap.put(s.charAt(right), cnt + 1);
            }
            else {
                counterMap.put(s.charAt(right), 1);
            }

            while (!isCounterOK(k)) {
                char l = s.charAt(left);
                int cnt = counterMap.get(l);
                if (cnt == 1) counterMap.remove(l);
                else counterMap.put(l, cnt - 1);
                left++;
            }
            answer = Math.max(answer, right - left + 1);
        }

        return answer;
    }

    public boolean isCounterOK(int k) {
        int maxCount = 0;
        int totalCount = 0;
        for (Entry<Character, Integer> entry : counterMap.entrySet()) {
            maxCount = Math.max(maxCount, entry.getValue());
            totalCount = totalCount + entry.getValue();
        }
        return totalCount - maxCount <= k;
    }
}
  • 패턴: Two Pointers, Hash Map / Hash Set, Greedy, Sliding Window
  • 설명: left와 right 두 포인터로 구간을 확장/축소하며 최적의 길이를 찾는다. 해시 맵으로 문자 빈도수를 추적하고, 전체 길이에서 최다 빈도수를 빼서 허용 횟수 k를 만족하는지 판단한다. 이때 윈도우의 최대 길이를 계속 갱신하므로 슬라이딩 윈도우와 그리디의 결합으로 풀이된다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(AlphabetSize)

피드백: 윈도우의 크기를 유지하며 최대 빈도 문자를 활용한다.

개선 제안: Counter 갱신 로직을 간결화하고, maxCount를 window 밖에서도 관리하는 방법을 고려해볼 수 있다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

class Solution {

Map<Character, Integer> counterMap = new HashMap<>();

public int characterReplacement(String s, int k) {

int left = 0;
int answer = 0;

for (int right = 0; right < s.length(); right++){
if(counterMap.containsKey(s.charAt(right))){

int cnt = counterMap.get(s.charAt(right));
counterMap.put(s.charAt(right), cnt + 1);
}
else {
counterMap.put(s.charAt(right), 1);
}

while (!isCounterOK(k)) {
char l = s.charAt(left);
int cnt = counterMap.get(l);
if (cnt == 1) counterMap.remove(l);
else counterMap.put(l, cnt - 1);
left++;
}
answer = Math.max(answer, right - left + 1);
Comment on lines +15 to +31

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

돌려보니 성능이 좋은 편은 아니라서 조금 더 최적화 시도해보셔도 좋을 거 같습니다.

}

return answer;
}

public boolean isCounterOK(int k) {
int maxCount = 0;
int totalCount = 0;
for (Entry<Character, Integer> entry : counterMap.entrySet()) {
maxCount = Math.max(maxCount, entry.getValue());
totalCount = totalCount + entry.getValue();
}
return totalCount - maxCount <= k;
}
Comment on lines +37 to +45

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이쪽에서 오버헤드가 살짝 있어 보이네요. 단순하게 빈도 배열만 사용해보시는 건 어떨까요?

}
36 changes: 36 additions & 0 deletions palindromic-substrings/sangbeenmoon.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

palindromic-substrings/sangbeenmoon.py
class Solution:
    def countSubstrings(self, s: str) -> int:
        dp = [[0] * (len(s) + 1) for _ in range(len(s) + 1)]

        def isPalindrome(start, end) -> bool:

            if end - start == 0:
                return True

            if end - start == 1 :
                return s[start] == s[end]

            if dp[start][end] == 1:
                return True

            if dp[start][end] == -1:
                return False    

            if s[start] == s[end]:
                return isPalindrome(start+1, end-1)    

            return False

        answer = 0

        for i in range(len(s) - 1, -1, -1):
            for j in range(i,len(s)):
                if isPalindrome(i,j):                    
                    dp[i][j] = 1
                    answer += 1
                else:
                    dp[i][j] = -1

        return answer
                
  • 패턴: Dynamic Programming
  • 설명: 문자열의 부분 문자열이 회문인지 여부를 DP로 저장해가며(메모이제이션) 중복 계산을 피하고 전체 부분 문자열을 탐색합니다. 주어진 풀이에서 dp 테이블로 회문 여부를 기록하고, 역순으로 시작점과 끝점을 늘려가며 결과를 누적합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n^2)
Space O(n^2)

피드백: isPalindrome 재귀와 DP 표를 섞어 부분 문자열의 회문 여부를 저장한다.

개선 제안: 현재 구현은 Python 구문과 DP 표 초기화가 다소 비효율적일 수 있어, 확정된 확장 방법으로 단순화하는 것을 고려해볼 수 있다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Solution:
def countSubstrings(self, s: str) -> int:
dp = [[0] * (len(s) + 1) for _ in range(len(s) + 1)]

def isPalindrome(start, end) -> bool:

if end - start == 0:
return True

if end - start == 1 :
return s[start] == s[end]

if dp[start][end] == 1:
return True

if dp[start][end] == -1:
return False

if s[start] == s[end]:
return isPalindrome(start+1, end-1)

return False

answer = 0

for i in range(len(s) - 1, -1, -1):
for j in range(i,len(s)):
if isPalindrome(i,j):
dp[i][j] = 1
answer += 1
else:
dp[i][j] = -1

return answer


Loading