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
35 changes: 35 additions & 0 deletions longest-repeating-character-replacement/dahyeong-yun.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/dahyeong-yun.java
/**
 * TC : O(n)
 *   - 문자열의 길이 n 만큼 반복하고 루프 안에서는 고정 길이를 반복하므로 O(n)
 * SC : O(1)
 *   - 26개 알파벳의 카운트를 위한 배열을 생성하므로 O(1)
 */
class Solution {
    public int characterReplacement(String s, int k) {
        int max = 0;

        int len = s.length();
        int deleteTarget = 0;
        int[] count = new int[26];
        for(int i=0; i<len; i++) {
            char c = s.charAt(i);
            count[c - 'A']++;

            
            int maxCountAlphabet = 0;
            int total = count[0];
            for(int j=1; j<26; j++) {
                total += count[j];    
                if(count[j] > count[maxCountAlphabet]) maxCountAlphabet = j;
            }

            if(total - count[maxCountAlphabet] <= k) {
                max = Math.max(max, total);
            } else {
                count[s.charAt(deleteTarget++) - 'A']--;
            }
        }

        return max;
    }
}
  • 패턴: Sliding Window, Greedy, Hash Map / Hash Set
  • 설명: 문자열 슬라이딩 윈도우로 부분 문자열 길이를 확장하며, 최대 반복 문자 수를 유지해 k만큼의 대체로 길이를 늘리는 탐욕적 전략을 사용합니다. 문자 빈도 배열을 이용해 현재 윈도우에서 필요한 교체 수를 계산합니다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(n) O(n)
Space O(1) O(1)

피드백: 26개 알파벳의 카운트를 유지하는 배열과 윈도우 좌/우 포인터를 사용해 부분 문자열의 문자 다수의 갯수를 트래킹한다.

개선 제안: 현재 구현은 최대 등장 문자 인덱스를 갱신하는 로직은 있지만 maxCountAlphabet의 값을 직접 인덱스로 비교하는 부분에서 혼란을 줄 수 있다. 더 명확하게 maxCountAlphabet 값을 문자 빈도 중 최댓값의 문자 인덱스로 관리하면 오류를 줄일 수 있다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* TC : O(n)
* - 문자열의 길이 n 만큼 반복하고 루프 안에서는 고정 길이를 반복하므로 O(n)
* SC : O(1)
* - 26개 알파벳의 카운트를 위한 배열을 생성하므로 O(1)
*/
class Solution {
public int characterReplacement(String s, int k) {
int max = 0;

int len = s.length();
int deleteTarget = 0;
int[] count = new int[26];
for(int i=0; i<len; i++) {
char c = s.charAt(i);
count[c - 'A']++;


int maxCountAlphabet = 0;
int total = count[0];
for(int j=1; j<26; j++) {
total += count[j];
if(count[j] > count[maxCountAlphabet]) maxCountAlphabet = j;
}

if(total - count[maxCountAlphabet] <= k) {
max = Math.max(max, total);
} else {
count[s.charAt(deleteTarget++) - 'A']--;
}
}

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.

코드 잘 읽었습니다!
count 26칸을 더한 total이 윈도우에 들어 있는 글자 수, 즉 윈도우 길이고, count[maxCountAlphabet]이 그 안에서 가장 많이 나온 문자의 개수네요.
그래서 total - count[maxCountAlphabet] <= k가 "바꿔야 할 개수가 k 이하인가"로 표현이 되네요!

저는 위 부분을 left, right와 windowLength로 표현했는데, 이번에 카운트의 합으로 length를 표현할 수 있다는걸 배워갑니다!

return max;
}
}
37 changes: 37 additions & 0 deletions palindromic-substrings/dahyeong-yun.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.

🏷️ 알고리즘 패턴 분석

palindromic-substrings/dahyeong-yun.java
/**
 * TC : O(n^2)
 *   - 문자열 길이 n 만큼 반복하고, 각 인덱스에서 n/2 만큼의 회문을 확인하므로 n * (n/2) => O(n^2)
 * SC : O(1)
 *   - 별도 유의미한 공간을 사용하지 않음 
 */
class Solution {
    public int countSubstrings(String s) {
        int len = s.length(), count = 0;

        for(int i = 0; i<len; i++) {
            int start = i, end = i;

            // 홀수 길이 회문 카운트
            while(
                start >= 0 && end < len && s.charAt(start) == s.charAt(end)
            ) {
                count++;
                start--;
                end++;
            }

            // 짝수 길이 회문 카운트
            start = i;
            end = i+1;
            while(
                start >= 0 && end < len && s.charAt(start) == s.charAt(end)
            ) {
                count++;
                start--;
                end++;
            }
        }

        return count;
    }
}
  • 패턴: Two Pointers, Monotonic Stack, Hash Map / Hash Set
  • 설명: 문자열의 각 인덱스에서 좌우로 확장하며 팰린드롬을 센다. 중앙 기준으로 홀수/짝수 길이의 회문을 확장하는 두 포인터 방식이 핵심 패턴이다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(n^2) O(n^2)
Space O(1) O(1)

피드백: 모든 위치에서 가운데를 기준으로 좌우로 확장하며 회문을 세는 방식으로 구현되어 있습니다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* TC : O(n^2)
* - 문자열 길이 n 만큼 반복하고, 각 인덱스에서 n/2 만큼의 회문을 확인하므로 n * (n/2) => O(n^2)
* SC : O(1)
* - 별도 유의미한 공간을 사용하지 않음
*/
class Solution {
public int countSubstrings(String s) {
int len = s.length(), count = 0;

for(int i = 0; i<len; i++) {
int start = i, end = i;

// 홀수 길이 회문 카운트
while(
start >= 0 && end < len && s.charAt(start) == s.charAt(end)
) {
count++;
start--;
end++;
}

// 짝수 길이 회문 카운트
start = i;
end = i+1;
while(
start >= 0 && end < len && s.charAt(start) == s.charAt(end)
) {
count++;
start--;
end++;
}
}

return count;
}
}
28 changes: 28 additions & 0 deletions reverse-bits/dahyeong-yun.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.

🏷️ 알고리즘 패턴 분석

reverse-bits/dahyeong-yun.java
/**
 * TC : O(1)
 *   - 32번의 루프를 2번 반복하므로 O(1)
 * SC : O(1)
 *   - 32칸 고정 길이의 stack이 필요하므로 O(1)
 */

class Solution {
    public int reverseBits(int n) {
        int answer = 0;
        Deque<Integer> stack = new ArrayDeque<>();

        for(int i = 0; i<32; i++) {
            stack.add(n % 2);
            n /= 2;
        }

        int j = 0;
        while(!stack.isEmpty()) {
            int bit = stack.getLast();
            stack.removeLast();
            answer += bit * Math.pow(2, j); 
            j += 1;
        }

        return answer;       
    }
}
  • 패턴: Stack / Queue, Bit Manipulation
  • 설명: 주어진 코드는 32비트 정수를 비트를 스택에 쌓고, 다시 꺼내며 자리수에 따라 반전된 비트를 구성한다. 비트 단위 조작과 스택 사용으로 비트 반전의 과정을 다룬다.

📊 시간/공간 복잡도 분석

복잡도
Time O(1)
Space O(1)

피드백: 고정된 32비트 길이의 루프와 고정 크기 스택으로 구성되어 있어 시간과 공간이 상수로 보장된다.

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

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

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.

한번 쉬프트 연산자를 활용해보시는건 어떨까요?
방금 저도 자바로 풀어봤는데 11줄까지 코드를 줄일수 있었어요!
if ((n & 1) == 1) answer |= 1;
이런 느낌으로 연산이 됩니다.

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.

또한 쉬프트연산자 쓰시면 별도의 스택같은 자료형이 필요 없기때문에 성능도 좋을거에요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* TC : O(1)
* - 32번의 루프를 2번 반복하므로 O(1)
* SC : O(1)
* - 32칸 고정 길이의 stack이 필요하므로 O(1)
*/

class Solution {

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.

저는 시프트로 비트를 하나씩 꺼내 자리에 얹는 방식으로 풀었는데, 스택에 담았다가 반대로 꺼내는 접근도 있군요. "뒤집는다"는 동작이 스택에 그대로 드러나서 의도가 잘 읽혔습니다.

두 부분이 눈에 들어 왔는데,

  1. getLast() 후 removeLast()는 pollLast() 하나로도 될 것 같습니다!
  2. 그리고 answer += bit * Math.pow(2, j) 부분인데, Math.pow가 double을 반환하다 보니 암묵적 (int) 로 변환됩니다. 이 부분을 bit << j로 쓰면 정수 연산만으로 끝나서, 20만 건 기준으로는 333ms에서 35ms로 줄어들더라고요. 복잡도는 똑같이 O(1)이라 통과에는 영향이 없지만 상수 차이가 있어서 공유드려봅니다!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

와우.. 상세한 설명 감사해요. 고민이 거기까지 미치지 못했는데 시야가 넓어지는 느낌이네요!

public int reverseBits(int n) {
int answer = 0;
Deque<Integer> stack = new ArrayDeque<>();

for(int i = 0; i<32; i++) {
stack.add(n % 2);
n /= 2;
}

int j = 0;
while(!stack.isEmpty()) {
int bit = stack.getLast();
stack.removeLast();
answer += bit * Math.pow(2, j);
j += 1;
}

return answer;
}
}
Loading