Skip to content
Open
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
53 changes: 53 additions & 0 deletions 3sum/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Two Pointers, Sorting, Hash Map / Hash Set
  • 설명: 3sum 문제에서 먼저 배열을 정렬한 뒤 고정 수와 두 포인터로 나머지 두 수를 찾는 방식으로 중복 제거와 목표 합 0 달성을 수행합니다. 공간은 상수에 가깝고 시간복잡도는 O(n^2)입니다.

📊 시간/공간 복잡도 분석

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

피드백: 정렬 후 원소 고정-투포인터 패턴으로 중복 제거를 잘 처리하고 있습니다. 모든 가능한 삼중합을 한 번씩 탐색합니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* 0. 풀이 개요
* - 시간복잡도 : O(n^2)
* - 공간복잡도 : O(1)
*/

class Solution {
/**
* 1. 풀이 과정
* 1.1 문제 이해
* - 세 수의 합이 0이 되는 중복 없는 전체 조합 찾기
* 1.2 제약 사항
* - 인덱스의 조합이 아닌 값의 조합이므로 배열의 원본을 유지할 필요는 없음
* - 조합의 중복을 어떻게 제외 시킬지가 관건
* 1.3 풀이 아이디어
* - 하나의 값이 고정되어 있으면 나머지 두 원소의 합이 고정값 * -1 이 되어야 하는 형태라고도 볼 수 있음
* - 배열의 인덱스는 몰라도 되므로 배열을 오름차순으로 정렬할 수 있음
* - 이때 고정값 하나는 반복문 안에서 루프를 돌면서 정하고, 나머지 두 수는 투 포인터로 원하는 조합을 찾을 수 있음
* - 배열이 오름차순으로 정렬되어 있으므로, 만약 합이 0 보다 크다면 숫자가 작아져야 하고, 0보다 작다면 숫자가 커져야 함.
* - 따라서 세 수의 합이 작아져야 한다면 우측 포인터를 좌측으로 옮기면서 숫자를 줄일 수 있고,
* - 합이 커져야 한다면 좌측 포인터를 우측으로 옮기면서 전체 합을 키울 수 있음.
* - 여기에 더해 중복을 제외하기 위해서 같은 수의 경우는 포인터를 건너뛰는 식으로 처리할 수 있음.
* - 시간복잡도는 배열의 원소(n)만큼 루프를 돌면서, 그 안에서 최악의 경우 n - 2 번 순회 하게 되므로 N(N-2) 가 되어 n^2 이라 볼 수 있음.
* - 추가적인 공간을 일부 만들기는 하는데 n에 차수에 대응하는 수가 없으므로 공간복잡도는 O(1)로 판단.
*/
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> answer = new ArrayList<>();

for(int i=0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}

Comment on lines +30 to +34

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.

nums[i] > 0 인 부분부터는 양수 + 양수 + 양수 가 되서 이 조건도 고려해보시면 좋을 거 같습니다!
ex: [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7]

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.

Suggested change
for(int i=0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for(int i=0; i < nums.length - 2; i++) {
if (nums[i] > 0) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}

이런 식으로 조기 종료를 할 수 있겠네요

int left = i+1;
int right = nums.length - 1;

while(left < right) {
if(nums[i] + nums[left] + nums[right] == 0) {
List<Integer> triple = List.of(nums[i], nums[left], nums[right]);
answer.add(triple);
while(left+1 < right && nums[left] == nums[left+1]) left++;
while(right > 0 && nums[right] == nums[right-1]) right--;
left++;
right--;
} else if(nums[i] + nums[left] + nums[right] > 0) right--;
else left++;
Comment on lines +38 to +47

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.

while(left+1 < right ..), while(right > 0 ..) 에서 right > 0도 left처럼 평가하는 것이 좋을 거 같습니다!

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.

Suggested change
while(left < right) {
if(nums[i] + nums[left] + nums[right] == 0) {
List<Integer> triple = List.of(nums[i], nums[left], nums[right]);
answer.add(triple);
while(left+1 < right && nums[left] == nums[left+1]) left++;
while(right > 0 && nums[right] == nums[right-1]) right--;
left++;
right--;
} else if(nums[i] + nums[left] + nums[right] > 0) right--;
else left++;
while(left < right) {
if(nums[i] + nums[left] + nums[right] == 0) {
List<Integer> triple = List.of(nums[i], nums[left], nums[right]);
answer.add(triple);
while(left < right && nums[left] == nums[left + 1]) left++;
while(left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if(nums[i] + nums[left] + nums[right] > 0) right--;
else left++;

좌측 포인터가 우측을 넘어가지 않는 선에서 끝내려는 거니, 해당 조건을 공통으로 넣는 식으로 가독성을 개선할 수 있을 것 같네요.

}
}

return answer;
}
}
36 changes: 36 additions & 0 deletions climbing-stairs/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Dynamic Programming
  • 설명: 계단 수 문제를 피보나치형 점화식으로 해결하며, 이전 단계의 결과를 이용해 현재 값을 구하는 전형적인 DP 패턴이다.

📊 시간/공간 복잡도 분석

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

피드백: 초기 경계조건을 명확히 두고 순차적으로 채워 나가는 DP 풀이입니다.

개선 제안: 메모리 사용을 줄이려면 두 변수로 롤링 배열로 구현하는 대안을 고려해볼 수 있습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* 0. 풀이 개요
* - 시간복잡도 : O(n)
* - 공간복잡도 : O(n)
*/
class Solution {
/**
* 1. 풀이 과정
* 1.1 이해
* - n 이 계단 수고 그 계단을 오르는 방법의 가짓 수를
* 1.2 제약
* - n이 1부터 45까지 임.
* 1.3 아이디어
* - 전형적인 DP 로 보이긴 함.
* - 현 단계로 오기 위해서는 전 단계에서 + 1을 하던지 전전단계에서 + 2 하던지 하는 방법이 있음
* - 즉 전 단계 까지의 가짓 수 + 전전 단계까지의 가짓 수 = 현 단계의 가짓 수 됨
* - 1번째와 2번째는 전전 단계가 없으므로 직접 계산 해준다.
* - n까지 순회하면서 계산하며, 각 단계의 가짓 수는 O(1)에 조회되므로 시간복잡도는 O(n) 이다.
* - 별도 배열이 n+1 만큼 필요하므로 O(n)의 공간복잡도를 가진다.
* 2. 최적화
* - 각 단계의 숫자는 계속 가지고 있을 필요 없이 별도 변수로 처리하면 공간복잡도를 O(1)로 최적화 할 수 있다.
*/
public int climbStairs(int n) {
if(n == 1) return 1;
if(n == 2) return 2;

int[] steps = new int[n+1];
steps[1] = 1;
steps[2] = 2;

for(int i=3; i<=n; i++) {
steps[i] = steps[i-1] + steps[i-2];
}
return steps[n];
}
Comment on lines +24 to +35

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.

가독성 좋은 코드인 거 같습니다!

}
43 changes: 43 additions & 0 deletions product-of-array-except-self/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Two Pointers, Dynamic Programming, Hash Map / Hash Set
  • 설명: 두 패턴의 핵심 아이디어는 왼쪽/오른쪽 누적 곱을 구해 각 원소를 제외한 곱을 구하는 방식이다. 배열을 두 번 순회하며 선행과 후행 값을 축적하는 방식은 최적해를 얻는 다층 누적 계산으로 분류할 수 있다. 또한 문제의 목표는 각 원소를 제외한 곱을 구하는 구조로 DP의 누적 관계를 활용하는 예이다.

📊 시간/공간 복잡도 분석

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

피드백: 왼쪽 누적곱과 오른쪽 누적곱을 이용해 한 배열에서 모든 원소를 구합니다. 공간을 상수로 줄이는 구현도 가능

개선 제안: 추가적인 최적화를 원하면 출력 배열 자체를 공간으로 활용하는 방식이 있습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* 0. 풀이 개요
* - 시간복잡도 : O(n)
* - 공간복잡도 : O(n)
*/
class Solution {
/**
* 1. 풀이 과정
* 1.1 이해
* - 각 배열의 원소가 본인을 제외한 모든 것이 곱해진 상태를 출력하면 됨.
* 1.2 제약
* - n이 2부터 10^5까지 임. 배열을 순회하는 경우 n^2은 어려워 보임(10^8 기준). 따라서 n log n 이하가 필요
* 1.3 아이디어
* - 사실 문제를 몇번 풀었어서 외워져 버림
* - 시각적으로 보이자면 2개의 배열을 활용하는 셈
* - | 배열 원소를 변수로 치환 | a | b | c | d |
* | prefix 의 상태 | 1 | 1 * a = a | a * b = ab | ab * c = abc |
* | suffix 의 상태 | bcd | cd | d | 1 |
* | prefix * suffix | bcd | acd | abd | abc |
* - 시간복잡도는 n 번씩 두번 순회 하므로 2n 번 순회로 O(n)이 됨.
* - 공간복잡도는 n 크기 만큼의 배열을 추가로 생성하므로 O(n)이 됨.
*/
public int[] productExceptSelf(int[] nums) {
int prefix = 1;
int suffix = 1;

int len = nums.length;
int[] answer = new int[len];

answer[0] = 1;
for(int i = 1; i < len; i++) {
answer[i] = prefix * nums[i-1];
prefix *= nums[i-1];
}

for(int i = len-1; i >= 0; i--) {
answer[i] = answer[i] * suffix;
suffix *= nums[i];
}
Comment on lines +24 to +39

@parkhojeong parkhojeong Jul 4, 2026

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.

prefix, suffix의 변수명이 값이 직관적이지는 않아서 값의 의미를 담으면 좋을 거 같습니다!
참고로 answer을 이용해서 prefix 제거하는 것도 가능할 거 같습니다~


return answer;
}
}
28 changes: 28 additions & 0 deletions valid-anagram/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Time Complexity Analysis Pattern?
  • 설명: 제시된 코드는 두 문자열을 정렬한 뒤 비교하는 방법으로 애너그램 여부를 판별한다. 이는 두 배열 정렬 후 비교하는 기본적인 아이디어이며, 패턴으로는 정렬(Sort) 자체를 이용한 해결과 그에 따른 비교를 포함한다.

📊 시간/공간 복잡도 분석

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

피드백: 문자 정렬으로 애너그램 여부를 판단하는 직관적인 접근입니다.

개선 제안: 추가로 해시맵을 이용해 선형 시간으로 풀이하는 방법도 있습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* 0. 풀이 개요
* - 시간복잡도 : O(n log n)
* - 공간복잡도 : O(n)
*/
class Solution {
/**
* 1. 풀이 과정
* 1.1 문제 이해
* - 애너그램이 가능한 문자열인지 판단하는 문제임. 두 문자열 s와 t가 주어지고, t가 s의 애너그램이라면 true를 반환
* 1.2 제약 사항
* - s, 와 t의 문자열의 길이가 5 * 10^4 이므로 문자열 길이 만큼 순회해야 한다면 O(n^2)은 불가능해 보임. O(n log n) 이하가 필요.
* - 문자는 반드시 영소문자로만 구성되어 있으나, 만약 Follow up 질문 처럼 유니코드를 포함해야 된다면 이를 포괄하는 자료형이 필요.
* 1.3 풀이 아이디어
* - 문자열을 정렬했을 때, 같은 문자열이라면 애너그램이 될 것.
* - 문자열의 character를 배열로 만들고 정렬하면, bulit-in 메서드에 의해 O(n log n)의 시간복잡도가 가짐,
* - 문자열의 길이만큼 character 배열이 필요하므로 2n 만큼의 공간이 더 필요하므로 O(n)의 공간복잡도를 가짐.
*/
public boolean isAnagram(String s, String t) {
char[] arrayS = s.toCharArray();
char[] arrayT = t.toCharArray();

Arrays.sort(arrayS);
Arrays.sort(arrayT);

return Arrays.equals(arrayS, arrayT);
}
Comment on lines +19 to +27

@parkhojeong parkhojeong Jul 4, 2026

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.

n log(n) 의 복잡도를 빈도 카운트를 이용해 개선해볼 수도 있을 거 같습니다!

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.

빈도 카운트를 이용해서 개선한다는 의미신거죠? 말씀주신대로 문자열의 Character 단위로 빈도 카운트 하는 방법도 있겠네요.

}
24 changes: 24 additions & 0 deletions validate-binary-search-tree/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Binary Search, Divide and Conquer, Depth-First Search
  • 설명: BST 유효성 검사에서 각 노드에 대해 범위를 재귀적으로 좁혀 확인하는 방식으로, 두 자식으로 분할하며 문제를 해결한다. 재귀 DFS를 활용하고 범위를 각각 왼쪽/오른쪽에 대해 좁혀 가는 방식은 divide and conquer와 DFS의 조합으로 볼 수 있다.

📊 시간/공간 복잡도 분석

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

피드백: 전위순회 방식으로 각 노드의 범위를 자식 노드에 전달하여 BST 조건을 확인합니다.

개선 제안: 스택 기반 순회로 재귀 깊이를 제거해 공간을 최적화할 수 있습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* 0. 풀이 개요
* - 시간복잡도 : O(n)
* - 공간복잡도 : O(n)
*/
class Solution {
/**
* 1.3 풀이 아이디어
* - root의 좌측은 전부 root.value 보다 작아야 하고, 우측은 더 커야함.
* - 각 부모 노드에 대해 좌측 자식 노드는 값이 더 작아야 하고, 우측은 더 커야함.
* - 이 검증을 매 노드에 반복하여 이진트리 여부를 체크할 수 있음
* - 모든 노드의 갯 수를 n 이라고 할 때 n 개의 노드를 모두 1번 방문하므로 O(n)의 시간복잡도를 가짐
* - 별도의 자료구조를 생성하지는 않지만, 콜 스택이 쌓인 상태를 감안 했을 때 최악의 경우 O(n)의 공간복잡도를 가짐.
*/
public boolean isValidBST(TreeNode root) {
return check(root, Long.MIN_VALUE, Long.MAX_VALUE);
}

boolean check(TreeNode cursor, long min, long max) {
if(cursor == null) return true; // 노드가 없는 경우 생략
if(cursor.val <= min || cursor.val >= max) return false;
return check(cursor.left, min, cursor.val) && check(cursor.right,cursor.val, max);
}
}
Loading