diff --git a/3sum/namuuCY.java b/3sum/namuuCY.java new file mode 100644 index 0000000000..a7692164a2 --- /dev/null +++ b/3sum/namuuCY.java @@ -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> answer = new ArrayList<>(); + + public List> 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 --; + } + } + } +} diff --git a/climbing-stairs/namuuCY.java b/climbing-stairs/namuuCY.java new file mode 100644 index 0000000000..86bc29cf77 --- /dev/null +++ b/climbing-stairs/namuuCY.java @@ -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; + } +} diff --git a/product-of-array-except-self/namuuCY.java b/product-of-array-except-self/namuuCY.java new file mode 100644 index 0000000000..e74979211a --- /dev/null +++ b/product-of-array-except-self/namuuCY.java @@ -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; + } +} diff --git a/valid-anagram/namuuCY.java b/valid-anagram/namuuCY.java new file mode 100644 index 0000000000..397015170a --- /dev/null +++ b/valid-anagram/namuuCY.java @@ -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; + } +} diff --git a/validate-binary-search-tree/namuuCY.java b/validate-binary-search-tree/namuuCY.java new file mode 100644 index 0000000000..86d1b00987 --- /dev/null +++ b/validate-binary-search-tree/namuuCY.java @@ -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; + } +}