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
54 changes: 54 additions & 0 deletions 3sum/ICE0208.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, Hash Map / Hash Set, Dynamic Programming
  • 설명: 정렬 후 i를 고정하고 나머지에서 Two Sum을 해법으로 사용하며, j를 증가시키며 방문 값들을 Hash Set으로 관리한다. 부분적으로 중복 제거를 위한 조건도 포함되어 있어, 두 포인터 대신 해시셋 기반의 탐색으로 구현되는 패턴이 보인다.

📊 시간/공간 복잡도 분석

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

피드백: 정렬 후 두 중첩 루프와 해시 집합으로 중복을 제거하는 방식이다. 최악의 경우 모든 쌍을 확인하므로 시간복잡도는 O(n^2)이고 추가 공간은 해시집합으로 O(n)이다.

개선 제안: 고려해볼 만한 대안: 기준값 고정 시 투포인터를 사용하면 해시세트 없이도 O(n^2) 시간과 O(1) 추가 공간으로 구현 가능하다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import java.util.*;

class Solution {
public List<List<Integer>> threeSum(int[] nums) {
/*
* 세 수의 합이 0이 되는 조합을 찾는다.
*
* nums[i]를 하나 고정하면,
* 나머지 두 수를 찾는 Two Sum 문제로 바꿀 수 있다.
*
* seen에는 현재 i 기준으로 지나온 값들을 저장한다.
* target이 seen에 있으면 nums[i] + target + nums[j] = 0 이다.
*
*
* 시간 복잡도: O(n^2)
* 공간 복잡도: O(n)
*/

Arrays.sort(nums);

List<List<Integer>> answer = new ArrayList<>();

for (int i = 0; i < nums.length; i++) {
// 같은 기준값은 한 번만 사용
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}

// 기준값이 양수면 합이 0이 될 수 없음
if (nums[i] > 0) {
break;
}

Set<Integer> seen = new HashSet<>();

for (int j = i + 1; j < nums.length; j++) {
int target = -nums[i] - nums[j];

if (seen.contains(target)) {
answer.add(Arrays.asList(nums[i], target, nums[j]));

// 같은 nums[j]는 중복 조합을 만들 수 있으므로 스킵
while (j + 1 < nums.length && nums[j] == nums[j + 1]) {
j++;
}
}

seen.add(nums[j]);
}
}

return answer;
}
}
35 changes: 35 additions & 0 deletions climbing-stairs/ICE0208.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, Greedy
  • 설명: 피보나치 유사식 dp[i] = dp[i-1] + dp[i-2]로 계단 수를 구하는 대표적인 DP 문제이며, 공간을 1차원 배열 없이 두 변수로 최적화하는 기법은 DP 패턴에 해당합니다. 그 외 특정 탐색이나 정렬 요소는 사용되지 않습니다.

📊 시간/공간 복잡도 분석

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

피드백: 두 변수만으로 이차식 점화식을 순회하며 필요한 값을 얻는다. 배열 전체를 사용하지 않아 공간을 절약한다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class Solution {
public int climbStairs(int n) {
/*
* i번째 계단에 도착하는 경우는 두 가지다.
*
* 1. i - 1번째 계단에서 한 칸 올라오는 경우
* 2. i - 2번째 계단에서 두 칸 올라오는 경우
*
* dp[i]를 i번째 계단에 도착하는 방법의 수라고 하면,
* dp[i] = dp[i - 1] + dp[i - 2] 이다. (i >= 3)
*
* 이때 dp[i]를 구하기 위해 필요한 값은 직전 값과 전전 값뿐이다.
* 따라서 dp 배열 전체를 만들지 않고 prev1, prev2 두 변수만 사용해 갱신한다.
*
* 시간 복잡도: O(n)
* 공간 복잡도: O(1)
*/

if (n <= 2) {
// 1번째 계단은 1가지, 2번째 계단은 2가지 방법으로 오를 수 있다.
return n;
}

int prev2 = 1; // dp[1]
int prev1 = 2; // dp[2]

for (int i = 3; i <= n; i++) {
int curr = prev1 + prev2; // dp[i]
prev2 = prev1;
prev1 = curr;
}

return prev1;
}
}
38 changes: 38 additions & 0 deletions product-of-array-except-self/ICE0208.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, Sliding Window, Hash Map / Hash Set, Dynamic Programming, Greedy, Divide and Conquer, Bit Manipulation, Trie, Union Find, Heap / Priority Queue, BFS, DFS, Backtracking, Monotonic Stack, Binary Search
  • 설명: 주요 아이디어는 왼쪽 곱과 오른쪽 곱을 누적해 결과를 구하는 방식으로, 추가 저장공간 없이 부분구간 누적 곱을 이용하는 기법이다. 두 번의 순회를 통해 각 위치의 좌우 누적 곱을 합성해 최종 결과를 얻는다.

📊 시간/공간 복잡도 분석

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

피드백: 좌우 누적곱을 한 번의 순회로 계산해 각 원소에 대해 자신을 제외한 곱을 얻는다. 추가 배열 없이 결과를 구성한다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class Solution {
public int[] productExceptSelf(int[] nums) {
/*
* 자기 자신을 제외한 모든 요소의 곱
* = 왼쪽 요소들의 곱 * 오른쪽 요소들의 곱
*
* 왼쪽에서 오른쪽으로 순회하면서 누적 곱을 구하면
* 각 요소 기준 왼쪽 요소들의 곱을 구할 수 있다.
*
* 반대로 오른쪽에서 왼쪽으로 순회하면서 누적 곱을 구하면
* 각 요소 기준 오른쪽 요소들의 곱을 구할 수 있다.
*
* 왼쪽 요소들의 곱과 오른쪽 요소들의 곱을 곱하면 정답이 된다.
*
* 시간 복잡도: O(n)
* 공간 복잡도: O(1)
* 단, 반환 배열 result는 제외한다.
*/
int n = nums.length;
int[] result = new int[n];

// 각 위치 기준 왼쪽 요소들의 곱을 result에 저장
int prefixProduct = 1;
for (int i = 0; i < n; i++) {
result[i] = prefixProduct;
prefixProduct *= nums[i];
}

// 각 위치 기준 오른쪽 요소들의 곱을 result에 반영
int suffixProduct = 1;
for (int i = n - 1; i >= 0; i--) {
result[i] *= suffixProduct;
suffixProduct *= nums[i];
}

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Hash Map / Hash Set, Bit Manipulation, Dynamic Programming, Two Pointers, Sliding Window, Fast & Slow Pointers, BFS, DFS, Backtracking, Divide and Conquer, Union Find, Trie, Monotonic Stack, Heap / Priority Queue, Greedy, Binary Search, Dynamic Programming, Bit Manipulation
  • 설명: 주어진 코드는 각 문자열의 알파벳 등장 횟수를 비교하기 위해 고정 배열로 카운트를 세고, 최종적으로 배열 비교로 동일성을 판단한다. 이는 해시 맵 없이도 빈도 수를 비교하는 전형적 패턴으로, 문자 빈도 기반 비교에 해당한다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n + m)
Space O(1)

피드백: 두 문자열의 문자 빈도를 비교하는 전형적인 해시 기반 방법이다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import java.util.Arrays;

class Solution {
/**
* n = s.length(), m = t.length()
* 각 문자열에서 알파벳별 등장 횟수를 센 뒤 비교한다.
* 시간 복잡도: O(n + m)
* 공간 복잡도: O(1) - 알파벳 소문자 26개만 사용하기 때문
*/
public boolean isAnagram(String s, String t) {
// 0: a, 1: b, ... , 25: z
int[] sCount = new int[26];
int[] tCount = new int[26];

for (int i = 0; i < s.length(); i++) {
sCount[s.charAt(i) - 'a']++;
}

for (int i = 0; i < t.length(); i++) {
tCount[t.charAt(i) - 'a']++;
}

return Arrays.equals(sCount, tCount);
}
}
28 changes: 28 additions & 0 deletions valid-anagram/ICE0208.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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Hash Map / Hash Set, Sorting
  • 설명: 두 문자열의 문자 빈도 비교로 동형 여부를 판단하는 방식은 해시 맵(또는 Counter)을 사용한 패턴에 해당한다. 또한 정렬 비교 방식은 기본적으로 정렬 알고리즘을 활용하는 일반적인 패턴으로 볼 수 있다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n + m)
Space O(1)

피드백: 두 문자열의 문자 빈도를 비교하는 전형적인 해시 기반 방법이다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from collections import Counter


class Solution_2:
def isAnagram(self, s: str, t: str) -> bool:
"""
n = len(s), m = len(t)

두 문자열의 각 문자 개수를 센 뒤 비교한다.

시간 복잡도: O(n + m)
공간 복잡도: O(1)
- 입력 문자가 알파벳 소문자 26개로 제한되기 때문
"""
return Counter(s) == Counter(t)


class Solution_01:
def isAnagram(self, s: str, t: str) -> bool:
"""
n = len(s), m = len(t)

두 문자열을 각각 정렬한 뒤 비교한다.

시간 복잡도: O(n log n + m log m)
공간 복잡도: O(n + m)
"""
return sorted(s) == sorted(t)
37 changes: 37 additions & 0 deletions validate-binary-search-tree/ICE0208.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, Depth-First Search, Divide and Conquer, Hash Map / Hash Set
  • 설명: 트리를 중위 순회 비슷한 방식으로 각 노드의 허용 범위를 재귀적으로 확인하고, 분할된 하위 트리에서 독립적으로 조건을 검사한다. 재귀를 통해 좌우 자식을 각각 다룬다는 점에서 DFS 및 분할된 문제 해결 패턴이 함께 작용한다.

📊 시간/공간 복잡도 분석

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

피드백: 각 노드를 한 번씩 방문하고 경계값을 업데이트한다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class Solution {
/*
* 현재 노드가 허용된 범위 안에 있는지 확인한다.
*
* 왼쪽 자식은 현재 노드보다 작아야 하므로,
* upperBound를 현재 노드 값으로 줄인다.
*
* 오른쪽 자식은 현재 노드보다 커야 하므로,
* lowerBound를 현재 노드 값으로 올린다.
*
* 시간 복잡도: O(n)
* - n은 전체 노드의 개수
* - 모든 노드를 한 번씩 검사한다.
*
* 공간 복잡도: O(h)
* - h는 트리의 높이
* - 재귀 호출 스택이 현재 탐색 중인 경로만큼 쌓인다.
* - 균형 잡힌 트리라면 O(log n) / 한쪽으로 치우친 트리라면 O(n)
*/
private boolean isValidWithinRange(TreeNode node, long lowerBound, long upperBound) {
if (node == null) {
return true;
}

// BST는 중복 값을 허용하지 않으므로 경계값과 같아도 false다.
if (node.val <= lowerBound || node.val >= upperBound) {
return false;
}

return isValidWithinRange(node.left, lowerBound, node.val)
&& isValidWithinRange(node.right, node.val, upperBound);
}

public boolean isValidBST(TreeNode root) {
return isValidWithinRange(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
}
Loading