diff --git a/3sum/eunhwa99.java b/3sum/eunhwa99.java index 47a9a3402..792d1a314 100644 --- a/3sum/eunhwa99.java +++ b/3sum/eunhwa99.java @@ -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> threeSum(int[] nums) { - Arrays.sort(nums); // Sort the array first - List> 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> threeSum(int[] nums){ + Arrays.sort(nums); + + List> result = new ArrayList<>(); + + for(int i=0;i0 && 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; } } - - diff --git a/climbing-stairs/eunhwa99.java b/climbing-stairs/eunhwa99.java index 1e11a7c65..66944fc11 100644 --- a/climbing-stairs/eunhwa99.java +++ b/climbing-stairs/eunhwa99.java @@ -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; } } diff --git a/product-of-array-except-self/eunhwa99.java b/product-of-array-except-self/eunhwa99.java index 975cc94ba..826273b4d 100644 --- a/product-of-array-except-self/eunhwa99.java +++ b/product-of-array-except-self/eunhwa99.java @@ -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; + } } + diff --git a/valid-anagram/eunhwa99.java b/valid-anagram/eunhwa99.java index 431d13f38..a5e8e2ff7 100644 --- a/valid-anagram/eunhwa99.java +++ b/valid-anagram/eunhwa99.java @@ -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 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(); } } + diff --git a/validate-binary-search-tree/eunhwa99.java b/validate-binary-search-tree/eunhwa99.java new file mode 100644 index 000000000..0ac09556e --- /dev/null +++ b/validate-binary-search-tree/eunhwa99.java @@ -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); + } +} + +