Skip to content
67 changes: 67 additions & 0 deletions 3sum/namuuCY.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, Binary Search, Sort
  • 설명: 코드는 정렬 후 고정 포인터와 좌우 포인터를 이용하는 3sum의 대표적인 Two Pointers 패턴을 사용합니다. 중복 제거와 합이 0일 때의 처리도 패턴의 핵심 요소입니다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.threeSum — Time: O(n^2) / Space: O(1)
복잡도
Time O(n^2)
Space O(1)

피드백: 정렬 후 중복 제거 로직을 통해 중복 결과를 피하는 구성이 잘 되어 있습니다.

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

풀이 2: Solution.searchByTwoPointer — Time: O(n^2) / Space: O(1)
복잡도
Time O(n^2)
Space O(1)

피드백: 중복 제거를 while 루프로 확실히 처리하고 있어 정확합니다.

개선 제안: 없음

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 문제 풀이 흐름
// 세 개의 변수. 만약 brute-force(3중 for문 -> 3000 ^ 3 이어서 시간복잡도 너무 높음.) -> 어떤 한 값을 고정해서 변수를 줄이자.
// 그러면 나머지 두 개는? 투 포인터 같은거 쓰면 안되나?
// 근데 중복되는 경우에 대해서 어떻게 고려함?
// 중복되는 경우가 너무 많다..
// 우선 정렬 먼저 -> 이후 하나 고정하고 나머지 투포인터 생각
// 중복되는거 생각나는대로, 음...

// N = nums.length라 할때
// 시간 복잡도 정렬 + for문 1개 * 길이 N 투포인터
// = O(N^2)
// 공간 복잡도 두 가지로 설명
// - Arrays.sort() 로 정렬 시 필요한 추가 공간(or 스택)을 따질 경우 : O(log N)
// - 따지지 않을 경우 : O(1)

class Solution {

int[] nums;
List<List<Integer>> answer = new ArrayList<>();

public List<List<Integer>> threeSum(int[] nums) {
this.nums = nums;
// 원본 배열 정렬
Arrays.sort(nums);

for (int fixed = 0; fixed < nums.length - 2; fixed++) {
// fixed가 이전의 값과 동일할 경우 skip
if (fixed > 0 && nums[fixed] == nums[fixed - 1]) continue;

// fixed가 양수이면 뒤에도 무조건 양수이므로 break
if (nums[fixed] > 0) break;

searchByTwoPointer(fixed);
}

return answer;
}

private void searchByTwoPointer(int fixedIdx) {
int leftIdx = fixedIdx + 1;
int rightIdx = nums.length - 1;

while (leftIdx < rightIdx) {
int sum = nums[fixedIdx] + nums[leftIdx] + nums[rightIdx];

if (sum == 0) {
answer.add(Arrays.asList(
nums[fixedIdx],
nums[leftIdx],
nums[rightIdx]
));

// 중복된것에 대해서 조정해줘야함.

leftIdx ++;
rightIdx --;

while (leftIdx < rightIdx && nums[leftIdx] == nums[leftIdx - 1]) leftIdx++;
while (leftIdx < rightIdx && nums[rightIdx] == nums[rightIdx + 1]) rightIdx--;
} else if (sum < 0) {
leftIdx ++;
} else {
rightIdx --;
}
}
}
}
28 changes: 28 additions & 0 deletions climbing-stairs/namuuCY.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 방식으로 해결한다. 상태를 이전 값들로 갱신하며 상수 공간으로 구현되어 패턴은 Dynamic Programming에 해당한다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.climbStairs — Time: O(n) / Space: O(1)
복잡도
Time O(n)
Space O(1)

피드백: 초기 경우에 대한 처리와 반복 갱신 로직이 명확합니다.

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

풀이 2: Solution.climbStairs (alternative) — Time: O(n) / Space: O(1)
복잡도
Time O(n)
Space O(1)

피드백: 주석에 비해 실제 호출부의 구현이 중심이므로 동일 풀이로 간주.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 문제 풀이 흐름
// 누가봐도 점화식 -> DP 문제이다.
// 자세히 보니 피보나치수열 같음
// 1,2번쨰 항일때만 주의해서 풀자.

// n에 대해서
// 시간복잡도 : O(n)
// 공간복잡도 : O(1)

class Solution {
public int climbStairs(int n) {
if (n == 1) return 1;
if (n == 2) return 2;

// 3 = 2 * [1] + [2]
// 4 = 2 * [2] + [3]
int doublePrev = 0;
int prev = 1;
int current = 2;

for (int i = 3 ; i <= n ; i++ ) {
doublePrev = prev;
prev = current;
current = doublePrev + prev;
}
return current;
}
}
77 changes: 77 additions & 0 deletions product-of-array-except-self/namuuCY.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.

이거 저도 잘 몰랐었는데요, 제대로 풀면 0의 갯수별로 엣지 케이스를 분리할 필요가 없더라고요

그리고 문제에서 보시면 아시다시피 나눗셈 연산자는 사용하지 말라고 되어 있어서요

You must write an algorithm that runs in O(n) time and without using the division operation.

그렇게 한번 시도해보시는것도 좋을것 같아요!

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.

말씀하신 것처럼, 제가 요구사항을 지키지 않은 풀이라 틀린풀이라고 보는게 맞는거 같습니다!
확인해서 새 풀이를 풀어보고, 추가했습니다.

또 리트코드 다른 분 풀이를 보니

static 영역을 추가하고
미리 작은 단위(길이가 2인 nums 배열)로 웜업을 해서 조금이나마 속도를 올리려고 꼼수를 쓴 게 있더라고요.
재미있어서 넣어봤습니다.

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, Greedy
  • 설명: 이 코드는 각 위치의 곱을 좌우의 누적곱으로 미리 계산하는 방식으로, 부분 문제를 합치고 전체 곱을 구하는 전형적인 누적곱 패턴이며, 배열을 두 번 순회하며 결과를 완성한다. 추가로 0 처리와 오버플로우 주의를 통해 문제의 경계 케이스를 다룬다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.productExceptSelf — Time: O(n) / Space: O(1)
복잡도
Time O(n)
Space O(1)

피드백: 공간을 상수로 유지하면서 두 방향 순회를 이용한 효율적 풀이.

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

풀이 2: Solution.prevSubmission — Time: O(n) / Space: O(1)
복잡도
Time O(n)
Space O(1)

피드백: 제로와 오버플로우 케이스를 다루는 보조 구현이 포함됩니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 문제 풀이 흐름 :
// 전체의 합에서 자기 자신만 뺀것을 생각하듯이, 전체의 곱에서 자기 자신만 나눈 것을 생각하자
// 이때, 중요한 것은 integer overflow와 0이 여러번 나올 떄 예외처리
// integer overflow : 문제에서는 답이 32 bit integer 라고 했지, 그 과정에서 생길 수 있는 곱들이 int범위라고 단정지을 수 없음
// 0의 개수에 따라 다르게 계산 :
// 0이 없을 때 : 상관없음.
// 1개만 있을 때 : 0인 곳에만 product 기입
// 2개만 있을 때 : 모두 0이 된다.

// n = nums.length 라 할때
// 시간복잡도 : O(n)
// 공간복잡도 : O(n)


class Solution {

static {
Solution warmup = new Solution();
for (int i = 0; i < 500; ++i) {
warmup.productExceptSelf(new int[2]);
}
}


public int[] productExceptSelf(int[] nums) {
int[] answer = new int[nums.length];

Arrays.fill(answer, 1);

int leftProduct = 1;
for (int i = 0 ; i < nums.length - 1; i ++) {
leftProduct *= nums[i];
answer[i + 1] *= leftProduct;
}

int rightProduct = 1;
for (int i = nums.length - 1 ; i > 0 ; i --) {
rightProduct *= nums[i];
answer[i - 1] *= rightProduct;
}

return answer;
}

public int[] prevSubmission(int[] nums) {
int zeros = 0;
long totalProduct = 1;

for (int number : nums) {
if (number == 0) {
zeros ++;
}
totalProduct *= number;
}

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

if (zeros == 0) {
for (int i = 0 ; i < nums.length; i ++ ) {
answer[i] = (int) (totalProduct / nums[i]);
}
} else if (zeros == 1) {
int nonZeroProduct = 1;
int zeroIdx = -1;
for (int i = 0 ; i < nums.length; i ++ ) {
if (nums[i] == 0) {
zeroIdx = i;
continue;
}
nonZeroProduct *= nums[i];
}
answer[zeroIdx] = nonZeroProduct;
}

return answer;
}
}
29 changes: 29 additions & 0 deletions valid-anagram/namuuCY.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, Array / Binary Counting, Bit Manipulation
  • 설명: 주어진 코드는 알파벳 빈도수를 26개 배열로 카운트하여 비교하는 방식으로 아나그램 여부를 판단합니다. 해시 맵 대신 고정 크기 배열로 카운트를 세는 점이 특징이며, 비교 단계에서 빈도수 일치 여부를 확인합니다.

📊 시간/공간 복잡도 분석

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

피드백: 빈도 배열로 빠르게 비교하는 일반적인 해결책입니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 문제 풀이 흐름
// 아나그램 : 글자 빈도가 같으면 항상 아나그램 관계
// 가장 먼저 : 전체 글자수가 같은지 비교
// 그 다음 -> 알파벳 별로 빈도수가 같은지 비교

// n = max(s의 길이, t의 길이)라고 했을때
// 시간복잡도 : O(n)
// 공간복잡도 : O(1)

class Solution {
public boolean isAnagram(String s, String t) {
int[] sCount = new int[26];
int[] tCount = new int[26];

if (s.length() != t.length()) return false;

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

for (int i = 0 ; i < 26 ; i++) {
if (sCount[i] == tCount[i]) continue;
return false;
}

return true;
}
}
62 changes: 62 additions & 0 deletions validate-binary-search-tree/namuuCY.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, Monotonic Stack, Hash Map / Hash Set, Depth-First Search, Backtracking, Divide and Conquer, Greedy, Two Pointers, Sliding Window, Breadth-First Search, DFS
  • 설명: 코드는 이진 트리를 중위순회하며 이전 값과 비교해 BST 여부를 확인하는 방식으로 구현되어 있어 DFS(재귀 기반) 패턴과 이와 관련된 Binary Search 트리 검증의 아이디어가 핵심이다. 추가로 현재 값과의 크기 비교를 통해 단조 증가를 유지하는 패턴이 담겨 있다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.isValidBST — Time: O(n) / Space: O(n)
복잡도
Time O(n)
Space O(n)

피드백: 재귀를 이용한 순회와 전역 변수로 음이 아닌 조건을 충족하며 올바르게 동작합니다.

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

풀이 2: Solution.visitNode — Time: O(n) / Space: O(n)
복잡도
Time O(n)
Space O(n)

피드백: 노드 방문 순서를 정확하게 유지합니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 문제 풀이 흐름
// 기억하기로는 트리 순회 하는 방식이 몇 가지 있던거로 기억하는데
// 왼쪽 자식 -> 부모 -> 오른쪽 자식 이 방식으로 순회하는 방식을 사용해야함.
// 그렇게 순회하도록 한 뒤, 순서대로 확인하는데 숫자가 증가하지 않는다면 invalid
// 순회 아이디어 : 재귀를 이용 + 이전 노드 방문 값을 항상 저장
// 맨 처음 노드 방문 값은 -2^32 로 하자 -> 맨 왼쪽 노드는 항상 그 다음이 되도록
// param : 현재 노드
// 왼쪽 자식이 있다면? 왼쪽 노드 방문,
// 없으면 무시
// 현재 노드 값 valid한지
// 오른쪽 자식이 있다면? 오른쪽 노드 방문

// n = node 갯수라고 한다면
// 시간복잡도 : O(n)
// 공간복잡도 : O(1)



/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {

long currentValue = -(1L << 33);

public boolean isValidBST(TreeNode root) {
return visitNode(root);
}


private boolean visitNode(TreeNode node) {
// 왼쪽 자식
if (node.left != null) {
boolean isValid = visitNode(node.left);
if (!isValid) return false;
}

// 현재 노드
if (currentValue >= node.val) return false;
currentValue = node.val;

// 오른쪽 자식
if (node.right != null) {
boolean isValid = visitNode(node.right);
if (!isValid) return false;
}

return true;
}
}
Loading