Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[eunhwa99] Week 02 Solutions #706

Merged
merged 12 commits into from
Dec 21, 2024
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
69 changes: 69 additions & 0 deletions 3sum/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* 문제 풀이
*/
// -4 -1 -1 0 2 2
// p1 p2 p3 sum < 0 -> p2 앞으로
// p1 p2 p3 sum < 0 -> p2 앞으로
// p1 p2 p3 sum < 0 -> p2 앞으로
// p1 p2p3 sum = 0 -> p1 앞으로
// p1 p2 p3 sum = 0 -> p3 값 다른 게 나올 때까지 이동
// p1 p2 p3 sum < 0 -> p2 앞으로 인데, p2 > p3 되므로 p1 앞으로
// p1 p2 p3 sum = 0 반복

/**
* 시간/공간 복잡도
*/
// 시간 복잡도 - 순회 횟수: n + (n-1) + (n-2) + .. => O(N^2)
// 공간 복잡도 - 배열을 정렬하는 데 O(n log n)의 공간 + 결과를 저장하는 answer 리스트는 문제의 요구에 따라 O(k)의 공간 = O(n log n) (배열 정렬을 위한 공간) + O(k) (결과 저장 공간)

class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums); // Sort the array first
List<List<Integer>> answer = new ArrayList<>();

for (int pointer1 = 0; pointer1 < nums.length - 2; pointer1++) {
// pointer1 의 중복 값 skip
if (pointer1 > 0 && nums[pointer1] == nums[pointer1 - 1]) {
continue;
}

int pointer2 = pointer1 + 1; // pointer2 는 pointer1 의 한 칸 앞
int pointer3 = nums.length - 1; // pointer3 는 끝에서 부터

while (pointer2 < pointer3) {
int sum = nums[pointer1] + nums[pointer2] + nums[pointer3];

if (sum < 0) {
pointer2++;
} else if (sum > 0) {
pointer3--;
} else {
// sum == 0
answer.add(Arrays.asList(nums[pointer1], nums[pointer2], nums[pointer3]));

// pointer2 중복 값 제거
while (pointer2 < pointer3 && nums[pointer2] == nums[pointer2 + 1]) {
pointer2++;
}

// pointer3 중복 값 제거
while (pointer2 < pointer3 && nums[pointer3] == nums[pointer3 - 1]) {
pointer3--;
}

// 두 값 모두 move
pointer2++;
pointer3--;
}
}
}

return answer;
}
}


25 changes: 25 additions & 0 deletions climbing-stairs/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* 문제 풀이
*/
// n=2 (1,1), (2) -> 2 가지
// n=3 (n=2, 1), (n=1, 2) -> 2 + 1 = 3가지
// n=4 (n=3, 1), (n=2, 2) -> 3 + 2 = 5가지
// n=5 (n=4, 1) , (n=3, 2)
// n=k (n=k-1, 1), (n=k-2, 2)

/**
* 시간/공간 복잡도
*/
// 시간 복잡도: 각 칸을 한 번씩 방문 -> O(n)
// 공간 복잡도: DP 배열 크기 -> O(n)
class Solution {
public int climbStairs(int n) {
int[] cntArray = new int[n + 1];
cntArray[0] = 1;
cntArray[1] = 1;
for (int i = 2; i <= n; ++i) {
cntArray[i] = cntArray[i - 1] + cntArray[i - 2];
}
return cntArray[n];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 시간 복잡도: 트리의 모든 노드를 한 번씩만 방문 -> O(n)
// 공간 복잡도: 재귀적으로 트리를 구성 ->
// 트리가 균형 잡힌 경우(즉, 트리의 높이가 log(n)인 경우), 재귀 호출 스택의 깊이는 O(log n)
// 트리가 편향된 형태(예: 모두 왼쪽 자식만 존재하는 경우)라면, 재귀 깊이는 O(n)

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 {

int preIdx = 0;

public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || inorder == null || preorder.length == 0 || inorder.length == 0) {
return null;
}

return build(preorder, inorder, 0, inorder.length - 1);
}


private TreeNode build(int[] preorder, int[] inorder, int inStart, int inEnd) {
// 재귀 종료 조건
// 포인터(인덱스)가 배열 길이를 넘었을
if (preIdx >= preorder.length || inStart > inEnd) {
return null;
}

// preorder 첫 번째 값은 해당 부분 트리의 root 이다.
int rootVal = preorder[preIdx++];
TreeNode root = new TreeNode(rootVal);

// inOrder 배열에서 root 값의 위치를 찾는다.
int rootIndex = -1;
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == rootVal) {
rootIndex = i;
break;
}
}

// root 값을 기준으로 inorder 배열의 왼쪽 부분 배열(inStart ~ rootIndex-1)은 root의 left tree,
// 오른쪽 부분 배열(rootIndex+1 ~ inEnd)은 root의 right tree 가 된다.
root.left = build(preorder, inorder, inStart, rootIndex - 1);
root.right = build(preorder, inorder, rootIndex + 1, inEnd);

return root;
}
}
49 changes: 49 additions & 0 deletions decode-ways/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import java.util.Arrays;

/**
* 문제 풀이
* 예제) 11106
* 가장 큰 수는 2자리 이므로 한 번에 갈 수 있는 칸은 1~2칸
* 현재 칸이 0일 경우는 칸 이동 불가
* 코드 범위는 1~26
*/

//시간 복잡도: 문자열의 각 인덱스를 한 번씩만 처리하므로 전체 O(n)
//공간 복잡도: dp 배열은 문자열의 길이에 비례하여 O(n) 공간을 차지

class Solution {

int stringSize = 0;
int[] dp;

// DP 이용
public int numDecodings(String s) {
stringSize = s.length();
dp = new int[stringSize + 1];
Arrays.fill(dp, -1);
return numDecodingHelper(s.toCharArray(), 0);
}

// dp -> O(N)
private int numDecodingHelper(char[] s, int curIndex) {
if (stringSize == curIndex) return 1;
if (s[curIndex] == '0') return 0; // 현재 칸이 0 -> 전진 불가
if (dp[curIndex] != -1) return dp[curIndex];

dp[curIndex] = 0; // 현재 노드 방문 체크
dp[curIndex] += numDecodingHelper(s, curIndex + 1); // 한 칸 전진

if ((curIndex + 1 < stringSize) && checkRange(s[curIndex], s[curIndex + 1])) // 2자리 코드가 10~26 안에 들어간다면
dp[curIndex] += numDecodingHelper(s, curIndex + 2); // 2칸 전진

return dp[curIndex];
}

private boolean checkRange(char left, char right) {
int leftNum = left - '0';
int rightNum = right - '0'; // 숫자로 변환

int num = leftNum * 10 + rightNum;
return (num >= 10 && num <= 26);
}
}
32 changes: 32 additions & 0 deletions valid-anagram/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import java.util.HashMap;
import java.util.Map;

/**
* 시간/공간 복잡도
*/
// 시간 복잡도: 문자열을 한 번씩만 방문 -> O(n)
// 공간 복잡도: 문자열 길이만큼 공간 필요(hashmap 크기) -> O(n)
class Solution {
public boolean isAnagram(String s, String t) {

// s 안의 문자들이 t 에도 동일한 횟수로 등장하는 지 확인
if (s.length() != t.length()) return false; // 두 문자열의 길이가 다르다면 아나그램이 아니다.

// 문자별 횟수 저장 map
Map<Character, Integer> sAlphabetCountMap = new HashMap<>();
for (char c : s.toCharArray()) { // 시간복잡도: O(n)
sAlphabetCountMap.put(c, sAlphabetCountMap.getOrDefault(c, 0) + 1);
}

for (char c : t.toCharArray()) { // 시간복잡도: O(n)
if (!sAlphabetCountMap.containsKey(c)) return false; // s에 t가 가진 문자열이 없다면 아나그램이 아니다.

int count = sAlphabetCountMap.get(c) - 1;
if (count == 0) sAlphabetCountMap.remove(c);
else sAlphabetCountMap.put(c, count);
}

// 모든 문자가 일치하면 해시맵이 비어 있어야 함
return sAlphabetCountMap.isEmpty();
}
}
Loading