Skip to content

[eunhwa99] Week 02 Solutions #1229

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

Merged
merged 9 commits into from
Apr 11, 2025
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
84 changes: 25 additions & 59 deletions 3sum/eunhwa99.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,34 @@
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--;
// 시간 복잡도: O(n^2) - nums 배열을 정렬하는 데 O(nlogn) 소요, 이후 이중 포인터로 O(n^2)
// 공간 복잡도: O(1) - 결과 리스트를 제외한 추가 공간 사용 없음
class Solution{
public List<List<Integer>> threeSum(int[] nums){
Arrays.sort(nums);

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

for(int i=0;i<nums.length-2;i++){
if(i>0 && nums[i] == nums[i-1]) continue; // 중복된 값 건너뛰기
int left = i+1;
int right = nums.length-1;

while(left < right){
int sum = nums[i] + nums[left] + nums[right];
if(sum == 0){
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
while(left < right && nums[left] == nums[left+1]) left++; // 중복된 값 건너뛰기
while(left < right && nums[right] == nums[right-1]) right--; // 중복된 값 건너뛰기
left++;
right--;
} else if(sum < 0){
left++;
} 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--;
right--;
}
}
}

return answer;
return result;
}
}


33 changes: 12 additions & 21 deletions climbing-stairs/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
/**
* 문제 풀이
*/
// 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) - n은 계단의 개수
// 공간 복잡도 O(1) - 상수 공간 사용
class Solution{
public int climbStairs(int n){
// 피보나치
int prev1 = 1; // 0번째 계단
int prev2 = 1; // 1번째 계단

/**
* 시간/공간 복잡도
*/
// 시간 복잡도: 각 칸을 한 번씩 방문 -> 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];
for(int i=2; i<=n; i++){
int current = prev1 + prev2;
prev1 = prev2;
prev2 = current;
}
return cntArray[n];
return prev2;
}
}
54 changes: 26 additions & 28 deletions product-of-array-except-self/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
// 풀이
// 현재 인덱스가 i 일 때, 문제에서 구하고자 하는 값은 아래와 같다.
// 나의 왼쪽(i-1)부터 처음까지의 곱 * 나의 오른쪽(i+1)부터 끝까지의 곱
// leftProduct[i-1] = 왼쪽(i-1)부터 처음까지의 곱
// rightProduct[i+1] = 오른쪽(i+1)부터 끝까지의 곱
// leftProduct는 처음부터 i까지 순회하면서 구하면 된다. leftProduct[i] = leftProduct[i-1] * (나 자신 = nums[i])
// rightProduct는 끝부터 시작해서 i까지 순회하면서 구하면 된다. rightProduct[i] = rightProduct[i+1] * (나 자신 = nums[i])

// 시간 복잡도: O(n) - nums 배열의 길이 n
// 공간 복잡도: O(n) - leftProduct와 rightProduct 배열을 사용
class Solution {

// DP 를 사용하면 시간 복잡도는 O(N)
// 공간 복잡도는 2개의 배열이 필요하고, 답으로 보낼 배열까지 해서 O(3*N) = O(N)
public int[] productExceptSelf(int[] nums) {
int[] leftProduct = new int[nums.length];
int[] rightProduct = new int[nums.length];

class Solution {
public int[] productExceptSelf(int[] nums) {
int len = nums.length;
int[] leftProduct = new int[len];
int[] rightProduct = new int[len];
for (int i = 0; i < nums.length; i++) {
if (i == 0) {
leftProduct[i] = 1;
} else {
leftProduct[i] = leftProduct[i - 1] * nums[i - 1];
}
}

leftProduct[0] = nums[0];
rightProduct[len - 1] = nums[len - 1];
for (int i = 1; i < len; ++i) {
leftProduct[i] = leftProduct[i - 1] * nums[i];
rightProduct[len - i - 1] = rightProduct[len - i] * nums[len - i - 1];
}
for (int i = nums.length - 1; i >= 0; i--) {
if (i == nums.length - 1) {
rightProduct[i] = 1;
} else {
rightProduct[i] = rightProduct[i + 1] * nums[i + 1];
}
}

int[] result = new int[len];
result[0] = rightProduct[1];
result[len - 1] = leftProduct[len - 2];
for (int i = 1; i < len - 1; ++i) {
result[i] = leftProduct[i - 1] * rightProduct[i + 1];
}
return result;
int[] result = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
result[i] = leftProduct[i] * rightProduct[i];
}
return result;
}
}


35 changes: 12 additions & 23 deletions valid-anagram/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
import java.util.HashMap;
import java.util.Map;

/**
* 시간/공간 복잡도
*/
// 시간 복잡도: 문자열을 한 번씩만 방문 -> O(n)
// 공간 복잡도: 문자열 길이만큼 공간 필요(hashmap 크기) -> O(n)
// 시간 복잡도: O(n) - 문자열 길이 n
// 공간 복잡도: O(1) - 알파벳 개수는 26개로 고정되어 있음
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length()!=t.length()) return false; // 길이가 다르면 false

// 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);
int[] letterCount = new int[26];
// 각 알파벳의 개수를 세기 위한 배열
for(int i = 0; i < s.length(); i++){
letterCount[s.charAt(i) - 'a']++;
letterCount[t.charAt(i) - 'a']--;
}

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);
for(int count : letterCount){
if(count != 0) return false;
}
return true;

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

27 changes: 27 additions & 0 deletions validate-binary-search-tree/eunhwa99.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 시간 복잡도 O(n) - n은 트리의 노드 개수
// 공간 복잡도 O(h) - h는 트리의 높이 (재귀 호출 스택 공간)
public class TreeNode{
int val;
TreeNode left;
TreeNode right;

TreeNode(int x) {
val = x;
}
}
class Solution{
public boolean isValidBST(TreeNode root) {
return isValidBSTHelper(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean isValidBSTHelper(TreeNode node, long min, long max) {
if (node == null) {
return true;
}
if (node.val <= min || node.val >= max) {
return false;
}
return isValidBSTHelper(node.left, min, node.val) && isValidBSTHelper(node.right, node.val, max);
}
}