diff --git a/3sum/Yjason-K.ts b/3sum/Yjason-K.ts new file mode 100644 index 000000000..1ee84ae66 --- /dev/null +++ b/3sum/Yjason-K.ts @@ -0,0 +1,53 @@ +/** + * 세 수의 합이 0이 되는 모든 고유한 조합을 찾는 함수 + * + * @param {number[]} nums - 정수 배열 + * @returns {number[][]} - 세 수의 합이 0이 되는 조합 배열 + * + * 1. 입력 배열 `nums`를 오름차순으로 정렬. + * 2. 이중 반복문을 사용하여 각 요소를 기준으로 `투 포인터(two-pointer)`를 이용해 조합을 탐색. + * 3. 중복 조합을 방지하기 위해 `Set`을 사용하여 결과 조합의 문자열을 저장. + * 4. 조건에 맞는 조합을 `result` 배열에 추가합니다. + * + * 시간 복잡도: + * - 정렬: O(n log n) + * - 이중 반복문 및 투 포인터: O(n^2) + * - 전체 시간 복잡도: O(n^2) + * + * 공간 복잡도: + * - `Set` 및 `result` 배열에 저장되는 고유 조합: O(k), k는 고유한 조합의 수 + * - 전체 공간 복잡도: O(n + k) + */ +function threeSum(nums: number[]): number[][] { + const sumSet = new Set(); + const result: number[][] = []; + nums.sort((a, b) => a - b); + + // 첫 번째 요소를 기준으로 반복문 수행 + for (let i = 0; i < nums.length - 2; i++) { + // 정렬 된 상태이기 때문에 시작점을 기준으로 다음 값 중복 비교 + if (i > 0 && nums[i] === nums[i - 1]) continue; + + let start = i + 1, end = nums.length - 1; + while (start < end) { + const sum = nums[i] + nums[start] + nums[end]; + if (sum > 0) { + end--; + } else if (sum < 0) { + start++; + } else { + const triplet = [nums[i], nums[start], nums[end]]; + const key = triplet.toString(); + if (!sumSet.has(key)) { + sumSet.add(key); + result.push(triplet); + } + start++; + end--; + } + } + } + + return result; +} + diff --git a/binary-tree-level-order-traversal/Gotprgmer.java b/binary-tree-level-order-traversal/Gotprgmer.java new file mode 100644 index 000000000..510c1f2e3 --- /dev/null +++ b/binary-tree-level-order-traversal/Gotprgmer.java @@ -0,0 +1,53 @@ +/** + * 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; + * } + * } + */ + +// preorder에서 맨 왼쪽을 root +// root값을 기반으로 inorder에서 인덱스를 찾는다 그리고 왼쪽 오른쪽 길이를 구한다. +// 다시 buildTree 함수를 재귀하는데 이때 위에서 구한 왼쪽 길이와 오른쪽길이를 참고해서 +// 왼쪽 buildTree +// value를 갱신 +// 오른쪽 buildTree를 갱신한다. + +// 시간복잡도 : O(N^2) -> 한쪽으로 치우친 트리일 경우 O(N)(index of) + T(N-1)이 될 수 있다. +// 위 식을 전개해보면 N + N-1 + N-2 + ... + 1 = N(N+1)/2 = O(N^2) +// 공간복잡도 : O(N) ->리트코드 but N길이의 리스트 크기*N번의 재귀호출이 일어날 수 있다. 따라서 O(N^2)가 아닌가...? +class SolutionGotprgmer { + public TreeNode buildTree(int[] preorder, int[] inorder) { + + if(preorder.length == 0 || indexOf(inorder,preorder[0]) == -1){ + return null; + } + TreeNode node = new TreeNode(); + + int root = preorder[0]; + int indexOfRoot = indexOf(inorder,root); + int leftCnt = indexOfRoot; + // 찾으면 + node.val = root; + node.left = buildTree(Arrays.copyOfRange(preorder,1,1+leftCnt),Arrays.copyOfRange(inorder,0,leftCnt)); + node.right = buildTree(Arrays.copyOfRange(preorder,1+leftCnt,preorder.length),Arrays.copyOfRange(inorder,1+leftCnt,inorder.length)); + return node; + } + public int indexOf(int[] intArray,int findNum){ + for(int i=0;i> combinationSum(int[] candidates, int target) { + /** + 1. understanding + - find all combinations, which sum to target + - can use same number multiple times + 2. strategy + - dp[target]: all combination, which sum to target + - dp[n + 1] = dp[n] | dp[1] + - [2,3,6,7], target = 7 + - dp[0] = [[]] + - dp[1] = [[]] + - dp[2] = [[2]] + - dp[3] = [[3]] + - dp[4] = dp[2] | dp[2] = [[2,2]] + - dp[5] = dp[2] | dp[3] = [[2,3]] + - dp[6] = dp[2] | dp[4] , dp[3] | dp[3] = [[2,2,2], [3,3]] + - dp[7] = dp[2] | dp[5], dp[3] | dp[4], dp[6] | dp[1], dp[7] = [[2,2,3],] + 3. complexity + - time: O(target * N) where N is length of candidates + - space: O(target * N) + */ + List>[] dp = new List[target + 1]; + for (int i = 0; i <= target; i++) { + dp[i] = new ArrayList<>(); + } + + dp[0].add(new ArrayList<>()); + + for (int candidate : candidates) { + for (int i = candidate; i <= target; i++) { + for (List combination : dp[i - candidate]) { + List newCombination = new ArrayList<>(combination); + newCombination.add(candidate); + dp[i].add(newCombination); + } + } + } + + return dp[target]; + } +} + diff --git a/combination-sum/HerrineKim.js b/combination-sum/HerrineKim.js new file mode 100644 index 000000000..4549f6f24 --- /dev/null +++ b/combination-sum/HerrineKim.js @@ -0,0 +1,30 @@ +// 시간 복잡도 : O(n^2) +// 공간 복잡도 : O(n) + +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ + +var combinationSum = function(candidates, target) { + const result = []; + + const backtrack = (remaining, combo, start) => { + if (remaining === 0) { + result.push([...combo]); + return; + } + + for (let i = start; i < candidates.length; i++) { + if (candidates[i] <= remaining) { + combo.push(candidates[i]); + backtrack(remaining - candidates[i], combo, i); + combo.pop(); + } + } + }; + + backtrack(target, [], 0); + return result; +}; diff --git a/combination-sum/HodaeSsi.py b/combination-sum/HodaeSsi.py new file mode 100644 index 000000000..a5cb50ce5 --- /dev/null +++ b/combination-sum/HodaeSsi.py @@ -0,0 +1,16 @@ +# 시간복잡도 : O(n * m) (n: target, m: len(candidates)) +# 공간복잡도 : O(n * m) +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + dp = [[] for _ in range(target + 1)] + dp[0] = [[]] + + for candidate in candidates: + for num in range(candidate, target + 1): + for combination in dp[num - candidate]: + temp = combination.copy() + temp.extend([candidate]) + dp[num].append(temp) + + return dp[target] + diff --git a/combination-sum/Real-Reason.kt b/combination-sum/Real-Reason.kt new file mode 100644 index 000000000..bce40e84f --- /dev/null +++ b/combination-sum/Real-Reason.kt @@ -0,0 +1,23 @@ +package leetcode_study + +fun combinationSum(candidates: IntArray, target: Int): List> { + val result = mutableListOf>() + val nums = ArrayDeque() + dfs(candidates, target, 0, 0, nums, result) + + return result +} + +private fun dfs(candidates: IntArray, target: Int, startIdx: Int, total: Int, nums: ArrayDeque, result: MutableList>) { + if (target < total) return + if (target == total) { + result.add(ArrayList(nums)) + return + } + for (i in startIdx..< candidates.size) { + val num = candidates[i] + nums.add(num) + dfs(candidates, target, i, total + num, nums, result) + nums.removeLast() + } +} diff --git a/combination-sum/Zioq.js b/combination-sum/Zioq.js new file mode 100644 index 000000000..cb019a87f --- /dev/null +++ b/combination-sum/Zioq.js @@ -0,0 +1,44 @@ +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +var combinationSum = function(candidates, target) { + let result = []; + + function find_combination(index, target, current) { + if (target === 0) { + result.push([...current]); + return; + } + + for (let i = index; i < candidates.length; i++) { + // Only proceed if current number doesn't exceed target + if (candidates[i] <= target) { + // Include current number in combination + current.push(candidates[i]); + + // Recursive call with: + // - same index i (allowing reuse of same number) + // - reduced target by current number + find_combination(i, target - candidates[i], current); + + // Backtrack: remove the last added number to try other combinations + current.pop(); + } + } + } + + find_combination(0, target, []); + return result; +}; + +/* + + + +*/ + +console.log(combinationSum([2,3,6,7], 7)) + + diff --git a/combination-sum/donghyeon95.java b/combination-sum/donghyeon95.java new file mode 100644 index 000000000..007154ab3 --- /dev/null +++ b/combination-sum/donghyeon95.java @@ -0,0 +1,60 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +class Solution { + private HashMap> dp = new HashMap<>(); + private HashSet set; + + public List> combinationSum(int[] candidates, int target) { + set = new HashSet<>(Arrays.stream(candidates).boxed().toList()); + recurse(target); + // Convert dp entries back to List> for return + return dp.getOrDefault(target, new ArrayList<>()).stream() + .map(str -> Arrays.stream(str.split(" ")) + .map(Integer::valueOf) + .collect(Collectors.toList())) + .collect(Collectors.toList()); + } + + public void recurse(int target) { + if (dp.containsKey(target)) return; + + List combinations = new ArrayList<>(); + for (int i = 1; i < target + 1; i++) { + if (set.contains(i)) { + int remaining = target - i; + recurse(remaining); + if (dp.containsKey(remaining)) { + for (String combination : dp.get(remaining)) { + List newCombination = new ArrayList<>(Arrays.stream(combination.split(" ")) + .map(Integer::valueOf) + .toList()); + newCombination.add(i); + newCombination.sort(Comparator.reverseOrder()); + + String newCombinationStr = newCombination.stream() + .map(String::valueOf) + .collect(Collectors.joining(" ")); + if (!combinations.contains(newCombinationStr)) { + combinations.add(newCombinationStr); + } + } + } + } + } + if (set.contains(target)) { + String singleCombination = String.valueOf(target); + if (!combinations.contains(singleCombination)) { + combinations.add(singleCombination); + } + } + dp.put(target, combinations); + } + +} + diff --git a/combination-sum/dusunax.py b/combination-sum/dusunax.py new file mode 100644 index 000000000..9126e5924 --- /dev/null +++ b/combination-sum/dusunax.py @@ -0,0 +1,39 @@ +''' +# 39. Combination Sum + +Backtracking for find combinations. + +## Time and Space Complexity + +``` +TC: O(n^2) +SC: O(n) +``` + +#### TC is O(n^2): +- iterating through the list in backtracking recursion to find combinations. = O(n^2) + +#### SC is O(n): +- using a list to store the combinations. = O(n) +''' + +class Solution: + # Backtracking = find combination + # candidate is distinct & can use multiple times. + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + result = [] + + def backtrack(currIdx, remain, combination): + if(remain == 0): + result.append(combination[:]) + return + if(remain < 0): + return + + for i in range(currIdx, len(candidates)): + combination.append(candidates[i]) + backtrack(i, remain - candidates[i], combination) + combination.pop() + + backtrack(0, target, [permutations]) + return result diff --git a/combination-sum/ekgns33.java b/combination-sum/ekgns33.java new file mode 100644 index 000000000..1e037722b --- /dev/null +++ b/combination-sum/ekgns33.java @@ -0,0 +1,42 @@ +import java.util.ArrayList; +import java.util.List; + +/** + input : array of distinct integers, single integer target + output : all unique combinations of candidates where chosen ones sum is target + constraints: + 1) can we use same integer multiple times? + yes + 2) input array can be empty? + no. [1, 30] + + + solution 1) + combination >> back-tracking + O(2^n) at most 2^30 << (2^10)^3 ~= 10^9 + + tc : O(2^n) sc : O(n) call stack + */ +class Solution { + public List> combinationSum(int[] candidates, int target) { + List> answer = new ArrayList<>(); + List prev = new ArrayList<>(); + backTrackingHelper(answer, prev, candidates, target, 0, 0); + return answer; + } + private void backTrackingHelper(List> ans, List prev, int[] cands, int target, int curSum, int p) { + if(curSum == target) { + ans.add(new ArrayList(prev)); + return; + } + if(p >= cands.length) return; + + for(int i = p; i< cands.length; i++) { + if((curSum + cands[i]) <= target) { + prev.add(cands[i]); + backTrackingHelper(ans, prev, cands, target, curSum + cands[i],i); + prev.remove(prev.size() - 1); + } + } + } +} diff --git a/combination-sum/eunhwa99.java b/combination-sum/eunhwa99.java new file mode 100644 index 000000000..5d6561a6b --- /dev/null +++ b/combination-sum/eunhwa99.java @@ -0,0 +1,32 @@ +import java.util.ArrayList; +import java.util.List; + +// backtracking +// 시간복잡도: 각 배열 원소마다 target을 만드는 데에 기여를 할 수도 있고 안 할 수도 있음 -> O(2^(target)) +// 공간복잡도: O(k * t) (k는 가능한 조합의 수, t는 각 조합의 크기) + +class Solution { + public List> combinationSum(int[] candidates, int target) { + List> result = new ArrayList<>(); + backtrack(candidates, target, 0, new ArrayList<>(), result); + return result; + } + + private void backtrack(int[] candidates, int target, int start, List currentCombination, List> result) { + // 목표값에 도달하면 현재 조합을 결과에 추가 + if (target == 0) { + result.add(new ArrayList<>(currentCombination)); + return; + } + + // 후보 숫자들을 탐색 + for (int i = start; i < candidates.length; i++) { + if (candidates[i] > target) continue; // 목표값보다 큰 숫자는 넘어감 + + currentCombination.add(candidates[i]); // 현재 숫자를 선택 + // 현재 숫자를 다시 사용할 수 있기 때문에 i를 그대로 두고 재귀 호출 + backtrack(candidates, target - candidates[i], i, currentCombination, result); + currentCombination.remove(currentCombination.size() - 1); // 백트래킹: 마지막 숫자 제거 + } + } +} diff --git a/combination-sum/forest000014.java b/combination-sum/forest000014.java new file mode 100644 index 000000000..0dffecf82 --- /dev/null +++ b/combination-sum/forest000014.java @@ -0,0 +1,41 @@ +/* +time complexity: O(nlogn) +- nums 배열(=candidates) 정렬: O(nlogn) +- 재귀 호출 부분은 시간 복잡도를 계산하기가 어렵네요.. candidates 배열을 정렬해두어서, target까지 남은 차이가 현재 확인하고 있는 candidate보다 작다면 루프를 빠져나오게 해서 O(n^t)보다는 작을 텐데, 이런 경우에는 어떻게 표현해야 적절한지 잘 모르겠습니다. + +space complexity: O(1) - 정답으로 사용한 이중 List는 제외 + +*/ + +class Solution { + ArrayList nums; + + public List> combinationSum(int[] candidates, int target) { + nums = Arrays.stream(candidates) + .boxed() + .collect(Collectors.toCollection(ArrayList::new)); + + Collections.sort(nums); + + return calc(target, 0); + } + + private List> calc(int target, int curr) { + if (target == 0) { + ArrayList> lists = new ArrayList<>(); + lists.add(new ArrayList<>()); + return lists; + } + + List> ret = new ArrayList<>(); + boolean found = false; + for (int i = curr; i < nums.size() && nums.get(i) <= target; i++) { + List> results = calc(target - nums.get(i), i); + for (List result : results) { + result.add(nums.get(i)); + ret.add(result); + } + } + return ret; + } +} diff --git a/combination-sum/gmlwls96.kt b/combination-sum/gmlwls96.kt new file mode 100644 index 000000000..c923dc8fe --- /dev/null +++ b/combination-sum/gmlwls96.kt @@ -0,0 +1,50 @@ +class Solution { + // 시간 : O(c^t), 공간 : O(t) + // 알고리즘 : dfs + val answerList = mutableSetOf>() + + fun combinationSum(candidates: IntArray, target: Int): List> { + candidates.sort() + combination( + candidates = candidates, + target = target, + current = 0, + currentList = listOf() + ) + return answerList.toList() + } + + private fun combination( + candidates: IntArray, + target: Int, + current: Int, + currentList: List + ) { + candidates.forEach { // candidates를 한개씩 꺼내 + val sum = current + it // 현재값을 더했을때 + when { + sum == target -> { // sum이 target과 동일한 값이면 answer 에 추가. + answerList.add( + currentList.toMutableList().apply { + add(it) + sort() + } + ) + } + + sum < target -> { // sum이 모자르면 다른 조합을 찾기 위해 재귀 호출. + combination( + candidates = candidates, + target = target, + current = sum, + currentList = currentList.toMutableList().apply { + add(it) + } + ) + } + + else -> return + } + } + } +} diff --git a/combination-sum/gwbaik9717.js b/combination-sum/gwbaik9717.js new file mode 100644 index 000000000..e5675acf5 --- /dev/null +++ b/combination-sum/gwbaik9717.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +var combinationSum = function (candidates, target) { + const answer = []; + const n = candidates.length; + const combi = (i, sum, arr) => { + for (let j = i; j < n; j++) { + const candidate = candidates[j]; + const newSum = sum + candidate; + + if (newSum === target) { + answer.push([...arr, candidate]); + continue; + } + + if (newSum > target) { + continue; + } + + if (newSum < target) { + combi(j, newSum, [...arr, candidate]); + } + } + }; + + combi(0, 0, []); + + return answer; +}; diff --git a/combination-sum/heypaprika.py b/combination-sum/heypaprika.py new file mode 100644 index 000000000..a94c06ed6 --- /dev/null +++ b/combination-sum/heypaprika.py @@ -0,0 +1,20 @@ +# 어렵네요ㅜ 보고 풀었습니다 + +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + ans = [] + def func(cur_remain, arr, idx): + if cur_remain == 0: + ans.append(list(arr)) + return + elif cur_remain < 0: + return + + for i in range(idx, len(candidates)): + arr.append(candidates[i]) + func(cur_remain - candidates[i], arr, i) + arr.pop() + + func(target, [], 0) + return ans + diff --git a/combination-sum/imsosleepy.java b/combination-sum/imsosleepy.java new file mode 100644 index 000000000..399f0a182 --- /dev/null +++ b/combination-sum/imsosleepy.java @@ -0,0 +1,26 @@ +// 처음엔 dp라 생각했는데, backtracking인걸 알아차리자마자 풀 수 있었음 +// 중간 결과를 계속 전달하는게 팁 +class Solution { + public List> combinationSum(int[] candidates, int target) { + List> result = new ArrayList<>(); + backtracking(candidates, target, 0, new ArrayList<>(), result); + return result; + } + + private void backtracking(int[] candidates, int target, int start, List tmp, List> result) { + if (target < 0) { + return; + } + + if (target == 0) { + result.add(new ArrayList<>(tmp)); + return; + } + + for (int i = start; i < candidates.length; i++) { + tmp.add(candidates[i]); + backtracking(candidates, target - candidates[i], i, tmp, result); + tmp.remove(tmp.size() - 1); + } + } +} diff --git a/combination-sum/jinah92.py b/combination-sum/jinah92.py new file mode 100644 index 000000000..ba0500ba0 --- /dev/null +++ b/combination-sum/jinah92.py @@ -0,0 +1,19 @@ +# O(T) time, O(C^T) space +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + results, nums = [], [] + + def dfs(start, total): + if total > target: + return + if total == target: + results.append(nums[:]) + for i in range(start, len(candidates)): + num = candidates[i] + nums.append(num) + dfs(i, total + num) + nums.pop() + + dfs(0, 0) + + return results diff --git a/combination-sum/mike2ox.ts b/combination-sum/mike2ox.ts new file mode 100644 index 000000000..1e774c0cc --- /dev/null +++ b/combination-sum/mike2ox.ts @@ -0,0 +1,27 @@ +/** + * source: https://leetcode.com/problems/combination-sum/ + * 풀이방법: 재귀를 이용하여 모든 조합을 탐색 + * + * 시간복잡도: O(n^m) (n: candidates의 길이, m: target을 만들기 위한 최대 반복 횟수) + * 공간복잡도: O(n^m) (n: candidates의 길이, m: target을 만들기 위한 최대 반복 횟수) + * + * Note + * - 당장에 구현하려다보니 재귀를 이용한 방법으로 구현. => 추후 리팩토링 필요 + */ +function combinationSum(candidates: number[], target: number): number[][] { + if (target === 0) return [[]]; + if (target < 0) return []; + + const result: number[][] = []; + + for (let i = 0; i < candidates.length; i++) { + const num = candidates[i]; + const subCombos = combinationSum(candidates.slice(i), target - num); + + for (const combo of subCombos) { + result.push([num, ...combo]); + } + } + + return result; +} diff --git a/combination-sum/minji-go.java b/combination-sum/minji-go.java new file mode 100644 index 000000000..ab895923a --- /dev/null +++ b/combination-sum/minji-go.java @@ -0,0 +1,33 @@ +/* + Problem: https://leetcode.com/problems/combination-sum/ + Description: return a list of all unique combinations of candidates where the chosen numbers sum to target + Concept: Array, Backtracking + Time Complexity: O(Nⁿ), Runtime 2ms + Space Complexity: O(N), Memory 44.88MB + + - Time Complexity, Space Complexity를 어떻게 계산해야할지 어렵네요 :( +*/ +class Solution { + public List> answer = new ArrayList<>(); + + public List> combinationSum(int[] candidates, int target) { + Arrays.sort(candidates); + findCombination(candidates, target, new ArrayList<>(), 0); + return answer; + } + + public void findCombination(int[] candidates, int target, List combination, int idx) { + if(target == 0) { + answer.add(new ArrayList<>(combination)); + return; + } + + for(int i=idx; i target) break; + + combination.add(candidates[i]); + findCombination(candidates, target-candidates[i], combination, i); + combination.remove(combination.size()-1); + } + } +} diff --git a/combination-sum/mintheon.java b/combination-sum/mintheon.java new file mode 100644 index 000000000..7c1e98966 --- /dev/null +++ b/combination-sum/mintheon.java @@ -0,0 +1,38 @@ +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +class Solution { + /** + 시간복잡도: O(2^n) + 공간복잡도: O(n) + */ + public List> combinationSum(int[] candidates, int target) { + List> answer = new ArrayList<>(); + Deque nums = new ArrayDeque<>(); + + backtracking(candidates, answer, nums, target, 0, 0); + + return answer; + } + + protected void backtracking(int[] candidates, List> answer, Deque nums, int target, int start, int total) { + if(total > target) { + return; + } + + if (total == target) { + answer.add(new ArrayList<>(nums)); + return; + } + + for(int i = start; i < candidates.length; i++) { + int num = candidates[i]; + nums.push(num); + + backtracking(candidates, answer, nums, target, i, total + num); + nums.pop(); + } + } +} diff --git a/combination-sum/mmyeon.ts b/combination-sum/mmyeon.ts new file mode 100644 index 000000000..e6f207953 --- /dev/null +++ b/combination-sum/mmyeon.ts @@ -0,0 +1,37 @@ +/** + * 접근 방법 : + * - 중복 포함하여 모든 조합 구해야 하니까 재귀함수로 풀기 + * - 재귀 호출로 탐색해야하는 타겟 줄여가면서 조합 만들기 + * - 동일 조합추가되지 않도록, startIndex 추가하여 다음 인덱스부터 순회하도록 제한 + * + * + * 시간복잡도 : O(n^target) + * - candidates 배열 길이 n만큼 재귀가 호출되고, 각 호출은 target 길이 만큼 중첩되니까 O(n^target) + * + * 공간복잡도 : O(target) + * - 최악의 경우 target만큼 재귀 호출되니까 O(target) + * + */ + +function combinationSum(candidates: number[], target: number): number[][] { + const result: number[][] = []; + + const dfs = (target: number, combination: number[], startIndex: number) => { + if (target === 0) { + result.push([...combination]); + return; + } + + if (target < 0) return; + + for (let i = startIndex; i < candidates.length; i++) { + combination.push(candidates[i]); + dfs(target - candidates[i], combination, i); + combination.pop(); + } + }; + + dfs(target, [], 0); + + return result; +} diff --git a/combination-sum/neverlish.go b/combination-sum/neverlish.go new file mode 100644 index 000000000..3e74ee415 --- /dev/null +++ b/combination-sum/neverlish.go @@ -0,0 +1,45 @@ +// 시간복잡도: O(n^2) +// 공간복잡도: O(n^2) + +package main + +import "testing" + +func TestCombinationSum(t *testing.T) { + result1 := combinationSum([]int{2, 3, 6, 7}, 7) + + if len(result1) != 2 { + t.Errorf("Expected 2, got %d", len(result1)) + } + + if len(result1[0]) != 3 && len(result1[1]) != 1 { + t.Errorf("Expected [[7], [2, 2, 3]], got %v", result1) + } + + result2 := combinationSum([]int{2, 3, 5}, 8) + + if len(result2) != 3 { + t.Errorf("Expected 3, got %d", len(result2)) + } + + if len(result2[0]) != 2 && len(result2[1]) != 3 && len(result2[2]) != 3 { + t.Errorf("Expected [[2, 2, 2, 2], [2, 3, 3], [3, 5]], got %v", result2) + } +} + +func combinationSum(candidates []int, target int) [][]int { + dp := make([][][]int, target+1) + + dp[0] = [][]int{{}} + + for _, candidate := range candidates { + for i := candidate; i <= target; i++ { + for _, combination := range dp[i-candidate] { + newCombination := append([]int{candidate}, combination...) + dp[i] = append(dp[i], newCombination) + } + } + } + + return dp[target] +} diff --git a/combination-sum/pmjuu.py b/combination-sum/pmjuu.py new file mode 100644 index 000000000..af2bfcb8e --- /dev/null +++ b/combination-sum/pmjuu.py @@ -0,0 +1,33 @@ +from typing import List + + +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + result = [] + + def backtrack(start, target, current_combination): + # 종료 조건 + if target == 0: + result.append(list(current_combination)) + return + if target < 0: + return + + # 백트래킹 + for i in range(start, len(candidates)): + current_combination.append(candidates[i]) + backtrack(i, target - candidates[i], current_combination) # 같은 원소를 여러 번 쓸 수 있도록 i를 그대로 둡니다. + current_combination.pop() # 돌아가서 다시 시도할 수 있도록 원소를 제거합니다. + + backtrack(0, target, []) + + return result + + +# 시간 복잡도: O(n^t) +# - 후보 리스트에서 각 숫자를 선택할 수 있기 때문에, n개의 후보를 사용해 t번의 탐색을 할 수 있습니다. +# - 따라서 최악의 경우 탐색 횟수는 O(n^t)로 볼 수 있습니다. +# +# 공간 복잡도: O(t) +# - 재귀 호출 스택의 깊이는 최대 target 값인 t에 비례하므로, 공간 복잡도는 O(t)입니다. +# - 또한, 현재까지 선택된 숫자들의 조합을 저장하는 공간도 최대 t개까지 저장하므로, 공간 복잡도는 O(t)입니다. diff --git a/combination-sum/sungjinwi.py b/combination-sum/sungjinwi.py new file mode 100644 index 000000000..0720a713c --- /dev/null +++ b/combination-sum/sungjinwi.py @@ -0,0 +1,20 @@ +""" + 시간 복잡도와 공간복잡도 추후 작성하겠습니다ㅠ + 풀이 보고 하루 뒤에 기억해서 해보려고 했는데도 한참 걸렸네요 +""" +class Solution: + def combinationSum(self, candidates: list[int], target: int) -> list[list[int]]: + ans = [] + comb = [] + def recur(n : int): + if sum(comb) > target : + return + elif sum(comb) == target : + return ans.append(comb.copy()) + else : + for i in range(n, len(candidates)) : + comb.append(candidates[i]) + recur(i) + comb.pop() + recur(0) + return ans diff --git a/combination-sum/taewanseoul.ts b/combination-sum/taewanseoul.ts new file mode 100644 index 000000000..73c2ba67b --- /dev/null +++ b/combination-sum/taewanseoul.ts @@ -0,0 +1,37 @@ +/** + * 39. Combination Sum + * Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order. + * The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different. + * The test cases are generated such that the number of unique combinations that sum up to target is less than 150 combinations for the given input. + * + * https://leetcode.com/problems/combination-sum/description/ + */ + +// O(n^m) time +// O(n) space +function combinationSum(candidates: number[], target: number): number[][] { + const res: number[][] = []; + dfs(candidates, 0, target, [], res); + return res; +} + +function dfs( + nums: number[], + start: number, + remaining: number, + path: number[], + res: number[][] +) { + if (remaining === 0) { + res.push([...path]); + return; + } + + for (let i = start; i < nums.length; i++) { + const num = nums[i]; + if (remaining - num < 0) continue; + path.push(num); + dfs(nums, i, remaining - num, path, res); + path.pop(); + } +} diff --git a/combination-sum/thispath98.py b/combination-sum/thispath98.py new file mode 100644 index 000000000..8a1904c18 --- /dev/null +++ b/combination-sum/thispath98.py @@ -0,0 +1,41 @@ +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + """ + Intuition: + 리스트의 각 원소는 중복해서 사용할 수 있다. + 그렇다면 target은 재귀적으로 원소를 사용해서 + 모든 경우의 수를 탐색한다. + + Time Complexity: + O(N^2 log N): + 초기에 리스트의 원소를 정렬하는 데에 O(N log N)이 소요된다. + 또한, 재귀 함수는 최대 N번 호출될 수 있으며 + 각 재귀 함수에서는 정렬하여 세트에 추가하는 경우 + O(N log N)이 소요되고, + N개의 원소에 대해 for문을 반복한다. + 따라서 O(N^2 log N)의 시간복잡도가 소요된다. + + Space Complexity: + O(N): + 최악의 경우 answer set에 대략 N개의 tuple이 저장된다. + 따라서 O(N)의 공간복잡도가 소요된다. + """ + candidates.sort() # O(N log N) + answer_set = set() + + + def dfs(n, arr): + if n == 0: + answer_set.add(tuple(sorted(arr))) # O(N log N) + return + + for candidate in candidates: # O(N) + if n >= candidate: + arr.append(candidate) + dfs(n - candidate, arr) + arr.pop() + + + dfs(target, []) # O(N) + answer = list(answer_set) + return answer diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/minji-go.java b/construct-binary-tree-from-preorder-and-inorder-traversal/minji-go.java index 1f7f3a769..bb5efde92 100644 --- a/construct-binary-tree-from-preorder-and-inorder-traversal/minji-go.java +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/minji-go.java @@ -2,7 +2,7 @@ Problem: https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ Description: Given two integer arrays preorder and inorder, construct and return the binary tree. Concept: Array, Hash Table, Divide and Conquer, Tree, Binary Tree - Time Complexity: O(NM), Runtime 2ms + Time Complexity: O(N²), Runtime 2ms Space Complexity: O(N), Memory 45.02MB */ import java.util.HashMap; diff --git a/maximum-product-subarray/sungjinwi.py b/maximum-product-subarray/sungjinwi.py new file mode 100644 index 000000000..e8f82028d --- /dev/null +++ b/maximum-product-subarray/sungjinwi.py @@ -0,0 +1,23 @@ +""" + /풀이 봐도 잘 이해 못해서 추가 코멘트/ + nums[i]가 그 전까지 subarray의 합 total보다 작은 음수인 케이스는 어떻게 되는거지 고민했는데 + ex) total : -1, nums[i] = -2 + 어차피 -1인 시점에 maxTotal이 업데이트 됐으므로 total은 nums[i]부터 더하기 시작한다는 의미로 -2로 설정한다는 것을 깨달음 + 따라서 이전까지 subarray의 합만 음수 양수 체크 + + TC : for문 한번 + => O(N) + SC : 추가적인 배열 등 메모리 쓰지 않으므로 + => O(1) +""" +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + total = nums[0] + maxTotal = nums[0] + for i in range(1, len(nums)) : + if (total < 0) : + total = nums[i] + else : + total += nums[i] + maxTotal = max(total, maxTotal) + return (maxTotal) diff --git a/maximum-subarray/GangBean.java b/maximum-subarray/GangBean.java new file mode 100644 index 000000000..1eebca0ab --- /dev/null +++ b/maximum-subarray/GangBean.java @@ -0,0 +1,28 @@ +class Solution { + public int maxSubArray(int[] nums) { + /** + 1. understanding + - integer array nums + - find largest subarray sum + 2. starategy + - calculate cumulative sum + - mem[i+1] = num[i+1] + mem[i] if (num[i+1] + mem[i] >= 0) else num[i+1] + 3. complexity + - time: O(N) + - space: O(1) + */ + int prev = 0; + int curr = 0; + int max = Integer.MIN_VALUE; + for (int i = 0 ; i < nums.length; i++) { + curr = nums[i]; + if (prev >= 0) { + curr += prev; + } + max = Math.max(max, curr); + prev = curr; + } + return max; + } +} + diff --git a/maximum-subarray/HerrineKim.js b/maximum-subarray/HerrineKim.js new file mode 100644 index 000000000..87ed8199c --- /dev/null +++ b/maximum-subarray/HerrineKim.js @@ -0,0 +1,18 @@ +// 시간 복잡도 : O(n) +// 공간 복잡도 : O(1) + +/** + * @param {number[]} nums + * @return {number} + */ +var maxSubArray = function(nums) { + let currentSum = nums[0]; + let maxSum = nums[0]; + + for (let i = 1; i < nums.length; i++) { + currentSum = Math.max(nums[i], currentSum + nums[i]); + maxSum = Math.max(maxSum, currentSum); + } + + return maxSum; +}; diff --git a/maximum-subarray/HodaeSsi.py b/maximum-subarray/HodaeSsi.py new file mode 100644 index 000000000..e0b1dbf0e --- /dev/null +++ b/maximum-subarray/HodaeSsi.py @@ -0,0 +1,13 @@ +# 시간복잡도 : O(N) +# 공간복잡도 : O(1) +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + global_sum = nums[0] + local_sum = nums[0] + + for i in range(1, len(nums)): + local_sum = max(nums[i], local_sum + nums[i]) + global_sum = max(local_sum, global_sum) + + return global_sum + diff --git a/maximum-subarray/Jeehay28.js b/maximum-subarray/Jeehay28.js new file mode 100644 index 000000000..a2ec53675 --- /dev/null +++ b/maximum-subarray/Jeehay28.js @@ -0,0 +1,48 @@ +/** + * @param {number[]} nums + * @return {number} + */ + +// Dynamic programming + + +// Optimized Solution: +// Time Complexity: O(n) +// Space Complexity: O(1) + + +var maxSubArray = function (nums) { + + let currentMax = nums[0]; + let globalMax = nums[0] + + for (let i = 1; i < nums.length; i++) { + + currentMax = Math.max(currentMax + nums[i], nums[i]); + globalMax = Math.max(currentMax, globalMax); + + } + + return globalMax; + +}; + + +// Time Complexity: O(n) +// Space Complexity: O(n) + +// var maxSubArray = function (nums) { + +// let dp = [nums[0]]; + +// for (let i = 1; i < nums.length; i++) { + +// dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]) + +// } + +// return Math.max(...dp) + +// }; + + diff --git a/maximum-subarray/YeomChaeeun.ts b/maximum-subarray/YeomChaeeun.ts new file mode 100644 index 000000000..ab0e24552 --- /dev/null +++ b/maximum-subarray/YeomChaeeun.ts @@ -0,0 +1,20 @@ +/** + * 연속되는 서브 배열로 최대 합을 구하기 + * 알고리즘 복잡도 + * - 시간 복잡도: O(n) + * - 공간 복잡도: O(1) + * @param nums + */ +function maxSubArray(nums: number[]): number { + if(nums.length === 1) return nums[0] + + let currentSum = nums[0] + let maxSum = nums[0] + for(let i = 1; i < nums.length; i++) { + currentSum = Math.max(nums[i], currentSum + nums[i]) + // 최대값 갱신 + maxSum = Math.max(maxSum, currentSum) + } + + return maxSum +} diff --git a/maximum-subarray/donghyeon95.java b/maximum-subarray/donghyeon95.java new file mode 100644 index 000000000..533e64227 --- /dev/null +++ b/maximum-subarray/donghyeon95.java @@ -0,0 +1,22 @@ +import java.util.Arrays; + +class Solution { + public int maxSubArray(int[] nums) { + int max = Integer.MIN_VALUE; + int current = 0; + + for (int num: nums) { + System.out.println(num + " " +max); + if (current + num >=0) { + max = Math.max(max, current+num); + current = current+num; + } else { + current = 0; + } + } + + // 전부 음수일 경우 => 가장 큰수 return + return max>=0? max: Arrays.stream(nums).max().getAsInt(); + } +} + diff --git a/maximum-subarray/dusunax.py b/maximum-subarray/dusunax.py new file mode 100644 index 000000000..01022cdcc --- /dev/null +++ b/maximum-subarray/dusunax.py @@ -0,0 +1,34 @@ +''' +# 53. Maximum Subarray + +- use Kadane's Algorithm for efficiently finding the maximum subarray sum. + +## Time and Space Complexity + +``` +TC: O(n) +SC: O(1) +``` + +#### TC is O(n): +- iterating through the list just once to find the maximum subarray sum. = O(n) + +#### SC is O(1): +- using a constant amount of extra space to store the current sum and the maximum sum. = O(1) +''' + +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + if len(nums) == 1: + return nums[0] + + currentSum = 0 # SC: O(1) + maxSum = nums[0] # SC: O(1) + + for i in range(len(nums)): # TC: O(n) + currentSum = max(currentSum + nums[i], nums[i]) # TC: O(1) + + if currentSum > maxSum: # TC: O(1) + maxSum = currentSum + + return maxSum diff --git a/maximum-subarray/ekgns33.java b/maximum-subarray/ekgns33.java new file mode 100644 index 000000000..f87957c53 --- /dev/null +++ b/maximum-subarray/ekgns33.java @@ -0,0 +1,41 @@ +/* +input : array of integer +output : largest sum of subarray +constraints : +1) is the input array not empty? +yes. at least one el +2) range of integers +[-10^4, 10^4] +3) maximum lenght of input +[10^5] +>> maximum sum = 10^5 * 10^4 = 10 ^ 9 < INTEGER + +sol1) brute force +nested for loop : O(n^2) +tc : O(n^2), sc : O(1) + +sol2) dp? +Subarray elements are continuous in the original array, so we can use dp. +let dp[i] represent the largest sum of a subarray where the ith element is the last element of the subarray. + +if dp[i-1] + curval < cur val : take curval +if dp[i-1] + cur val >= curval : take dp[i-1] + curval +tc : O(n) sc : O(n) + */ +class Solution { + public int maxSubArray(int[] nums) { + int n = nums.length; + int[] dp = new int[n]; + int maxSum = nums[0]; + dp[0] = nums[0]; + for(int i = 1; i < n; i++) { + if(dp[i-1] + nums[i] < nums[i]) { + dp[i] = nums[i]; + } else { + dp[i] = nums[i] + dp[i-1]; + } + maxSum = Math.max(maxSum, dp[i]); + } + return maxSum; + } +} diff --git a/maximum-subarray/eunhwa99.java b/maximum-subarray/eunhwa99.java new file mode 100644 index 000000000..0383bfbdc --- /dev/null +++ b/maximum-subarray/eunhwa99.java @@ -0,0 +1,15 @@ +// 시간 복잡도: DP -> O(N) +// 공간 복잡도: nums 배열 크기 - O(N) + +class Solution { + public int maxSubArray(int[] nums) { + int currentSum = nums[0]; + int maxSum = currentSum; + for (int i = 1; i < nums.length; ++i) { + currentSum = Math.max(currentSum + nums[i], nums[i]); + maxSum = Math.max(maxSum, currentSum); + } + + return maxSum; + } +} diff --git a/maximum-subarray/forest000014.java b/maximum-subarray/forest000014.java new file mode 100644 index 000000000..538195074 --- /dev/null +++ b/maximum-subarray/forest000014.java @@ -0,0 +1,38 @@ +/* +time complexity: O(n) +space complexity: O(1) + +왼쪽에서부터 누적합을 구하되, 더한 값이 음수가 되는 순간 지금까지 더한 값을 버린다. (즉, 지금까지의 원소는 모두 subarray에서 제외한다.) 이렇게 누적합을 계산하면서, 누적합의 최대값을 찾으면 답이 된다. + +단, 모든 원소가 음수인 경우는 예외적으로 처리해준다. + +*/ + +class Solution { + public int maxSubArray(int[] nums) { + int n = nums.length; + int ans = -10001; + int max = -10001; + int sum = 0; + for (int i = 0; i < n; i++) { + if (sum + nums[i] < 0) { + sum = 0; + } else { + sum += nums[i]; + } + if (sum > ans) { + ans = sum; + } + if (max < nums[i]) { + max = nums[i]; + } + } + + // 모두 음수인 경우의 예외 처리 + if (max < 0) { + return max; + } else { + return ans; + } + } +} diff --git a/maximum-subarray/gmlwls96.kt b/maximum-subarray/gmlwls96.kt new file mode 100644 index 000000000..552d391f1 --- /dev/null +++ b/maximum-subarray/gmlwls96.kt @@ -0,0 +1,22 @@ +class Solution { + fun maxSubArray(nums: IntArray): Int { + val dp = Array(nums.size) { y -> + IntArray(nums.size) { x -> + if (y == x) { + nums[y] + } else { + 0 + } + } + } + + var max = dp[0][0] + for (y in nums.indices) { + for (x in y + 1..nums.lastIndex) { + dp[y][x] = dp[y][x - 1] + nums[x] + max = max(max, dp[y][x]) + } + } + return max + } +} diff --git a/maximum-subarray/gwbaik9717.js b/maximum-subarray/gwbaik9717.js new file mode 100644 index 000000000..e54d84a52 --- /dev/null +++ b/maximum-subarray/gwbaik9717.js @@ -0,0 +1,25 @@ +// Time complexity: O(n) +// Space complexity: O(1) + +/** + * @param {number[]} nums + * @return {number} + */ +var maxSubArray = function (nums) { + const n = nums.length; + const dp = [0, 0]; + + let answer = Number.MIN_SAFE_INTEGER; + + for (let i = 1; i <= n; i++) { + if (i % 2 !== 0) { + dp[1] = Math.max(dp[0] + nums[i - 1], nums[i - 1]); + answer = Math.max(answer, dp[1]); + } else { + dp[0] = Math.max(dp[1] + nums[i - 1], nums[i - 1]); + answer = Math.max(answer, dp[0]); + } + } + + return answer; +}; diff --git a/maximum-subarray/heypaprika.py b/maximum-subarray/heypaprika.py new file mode 100644 index 000000000..7493708b2 --- /dev/null +++ b/maximum-subarray/heypaprika.py @@ -0,0 +1,14 @@ +""" +복잡도 : 예상 -> 예상한 이유 + +시간 복잡도 : O(n) -> len(nums) 만큼 반복 +공간 복잡도 : O(n) -> len(nums) 크기의 배열 a 생성 +""" +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + a = [0] * len(nums) + a[0] = nums[0] + for i in range(1, len(nums)): + a[i] = max(nums[i], nums[i]+a[i-1]) + return max(a) + diff --git a/maximum-subarray/imsosleepy.java b/maximum-subarray/imsosleepy.java new file mode 100644 index 000000000..a6d977b22 --- /dev/null +++ b/maximum-subarray/imsosleepy.java @@ -0,0 +1,16 @@ +// subarray = "연속된 값"의 합을 요구 함 그래서 간단한 풀이가 가능하다. +// 이전 인덱스나 값들을 기억할 필요가 없어서 누적합 느낌으로 풀 수 있다. +// 키포인트는 이전까지의 합보다 다음 숫자가 큰 경우의 수가 존재한다는 것 +class Solution { + public int maxSubArray(int[] nums) { + int max = nums[0]; + int current = nums[0]; + + for (int i = 1; i < nums.length; i++) { + current = Math.max(nums[i], current + nums[i]); + max = Math.max(max, current); + } + + return max; + } +} diff --git a/maximum-subarray/jinah92.py b/maximum-subarray/jinah92.py new file mode 100644 index 000000000..dcf0d88b5 --- /dev/null +++ b/maximum-subarray/jinah92.py @@ -0,0 +1,14 @@ +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + num_set = {} + result = -math.inf + + for idx, num in enumerate(nums): + if idx == 0: + num_set[idx] = max(nums[0], result) + else: + num_set[idx] = max(num, num_set[idx-1] + num) + tmp_sum = num_set[idx] + result = max(result, tmp_sum) + + return result diff --git a/maximum-subarray/mike2ox.ts b/maximum-subarray/mike2ox.ts new file mode 100644 index 000000000..2c6d74a31 --- /dev/null +++ b/maximum-subarray/mike2ox.ts @@ -0,0 +1,22 @@ +/** + * source: https://leetcode.com/problems/maximum-subarray/ + * 풀이방법: 현재 위치까지의 최대 합을 저장하면서 전체 최대 합을 갱신 + * 시간복잡도: O(n) (n: nums의 길이) + * 공간복잡도: O(1) (상수 공간만 사용) + */ +function maxSubArray(nums: number[]): number { + // 배열이 비어있는 경우 + if (nums.length === 0) return 0; + + let result = nums[0]; // 전체 최대 합(초기값은 첫 번째 요소) + let current = nums[0]; // 현재 위치까지의 최대 합 + + for (let i = 1; i < nums.length; i++) { + // 현재 요소를 더한 값과 현재 요소 중 큰 값을 선택 + current = Math.max(nums[i], current + nums[i]); + // 전체 최대 합 갱신 + result = Math.max(result, current); + } + + return result; +} diff --git a/maximum-subarray/minji-go.java b/maximum-subarray/minji-go.java new file mode 100644 index 000000000..617d215a7 --- /dev/null +++ b/maximum-subarray/minji-go.java @@ -0,0 +1,18 @@ +/* + Problem: https://leetcode.com/problems/maximum-subarray/ + Description: return the largest sum of the subarray, contiguous non-empty sequence of elements within an array. + Concept: Array, Divide and Conquer, Dynamic Programming + Time Complexity: O(N), Runtime 1ms + Space Complexity: O(1), Memory 57.02MB +*/ +class Solution { + public int maxSubArray(int[] nums) { + int max = nums[0]; + int sum = nums[0]; + for(int i=1; i result { + result = num + } + } + + return result +} + +func maxSubArray(nums []int) int { + dp := make([]int, len(nums)) + + dp[0] = nums[0] + + for index, num := range nums[1:] { + dp[index+1] = max(0, dp[index]) + num + + } + + return max(dp...) +} diff --git a/maximum-subarray/pmjuu.py b/maximum-subarray/pmjuu.py new file mode 100644 index 000000000..0cf0aa22e --- /dev/null +++ b/maximum-subarray/pmjuu.py @@ -0,0 +1,20 @@ +from typing import List + + +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + largest_sum = -float('inf') + current_sum = -float('inf') + + for num in nums: + current_sum = max(current_sum + num, num) + largest_sum = max(largest_sum, current_sum) + + return largest_sum + + +# 시간 복잡도: O(n) +# - nums 배열을 한 번 순회하며 각 요소에 대해 최대 부분 배열 합을 계산하므로 시간 복잡도는 O(n)입니다. +# +# 공간 복잡도: O(1) +# - 추가로 사용하는 변수는 largest_sum과 current_sum 두 개뿐이므로 공간 복잡도는 O(1)입니다. diff --git a/maximum-subarray/thispath98.py b/maximum-subarray/thispath98.py new file mode 100644 index 000000000..1cae0041b --- /dev/null +++ b/maximum-subarray/thispath98.py @@ -0,0 +1,37 @@ +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + """ + Intuition: + 이전까지의 누적합에서 현재 원소를 추가할지 말지에 대한 + 결정을 매 iteration마다 반복한다. + 현재 원소를 추가했을 경우(누적합 + 현재 원소)와 + 현재 원소를 시작으로 하는 경우(현재 원소)를 비교하여 + dp 배열을 갱신한다. + + Time Complexity: + O(N): + 리스트를 1번 순회하며 답을 찾으므로, + O(N)의 시간복잡도가 소요된다. + + Space Complexity: + O(N): + dp 배열에 N개의 time step을 저장하므로 + O(N)의 공간복잡도가 소요된다. + + Key takeaway: + 초기에는 two pointer 방식을 생각했으나 + 해결을 하지 못해서 답안을 확인했다. + O(N)의 시간복잡도를 가지는 경우, DP도 풀이가 + 될 수 있음을 인지하자. + """ + dp = [0 for _ in nums] + dp[0] = nums[0] + for i in range(1, len(nums)): + cumsum = dp[i - 1] + nums[i] + cur = nums[i] + if cumsum > cur: + dp[i] = cumsum + else: + dp[i] = cur + + return max(dp) diff --git a/product-of-array-except-self/EcoFriendlyAppleSu.kt b/product-of-array-except-self/EcoFriendlyAppleSu.kt new file mode 100644 index 000000000..0d02151c2 --- /dev/null +++ b/product-of-array-except-self/EcoFriendlyAppleSu.kt @@ -0,0 +1,43 @@ +package leetcode_study + +/* +* 주어진 배열에서 자신 요소를 제외한 나머지 요소의 곱한 배열을 구하는 문제 +* 문제에세 O(n)의 시간 복잡도를 요구하였으나 방법이 떠오르지 않아 고민 후 정답 참조. +* 기준 요소를 중심으로 왼쪽의 총 곱, 오른쪽의 총 곱을 진행하게 되었을 때, 문제를 O(n)의 시간 복잡도로 해결할 수 있음. +* 시간 복잡도: O(n^2) +* 공간 복잡도: O(n) +* */ +fun productExceptSelf00(nums: IntArray): IntArray { + val result = mutableListOf() + + for (i in nums.indices) { + var temp = 1 + for (j in nums.indices) { + if (i == j) continue + temp *= nums[j] + } + result.add(temp) + } + return result.toIntArray() +} + +/* +* 시간 복잡도: O(n) +* 공간 복잡도: O(n) +* */ +fun productExceptSelf01(nums: IntArray): IntArray { + val result = IntArray(nums.size) + + var leftProduct = 1 + for (i in nums.indices) { + result[i] = leftProduct + leftProduct = leftProduct * nums[i] + } + + var rightProduct = 1 + for (i in nums.indices.reversed()) { + result[i] = result[i] * rightProduct + rightProduct = rightProduct * nums[i] + } + return result +} diff --git a/product-of-array-except-self/GangBean.java b/product-of-array-except-self/GangBean.java new file mode 100644 index 000000000..cf53f48c1 --- /dev/null +++ b/product-of-array-except-self/GangBean.java @@ -0,0 +1,56 @@ +class Solution { + public int[] productExceptSelf(int[] nums) { + /** + 1. understanding + - given integer array nums + - product of which's all elements except that element + - should be under O(N) time complexity + - should not use division operation + 2. strategy + - brute force: O(n^2) + - for every elements, calculate product of other elements + - 1: 2 * [3 * 4] + - 2: 1 * [3 * 4] + - 3: [1 * 2] * 4 + - 4: [1 * 2] * 3 + - dynamic programming + - assign array mem to memorize product till that idx + - mem memorize in ascending order product value and reverse order product value + 3. complexity + - time: O(N) + - space: O(N) + */ + // 1. assign array variable mem + int[][] mem = new int[nums.length][]; + for (int i = 0 ; i < nums.length; i++) { + mem[i] = new int[2]; + } + + // 2. calculate product values + for (int i = 0 ; i < nums.length; i++) { // O(N) + if (i == 0) { + mem[i][0] = nums[i]; + continue; + } + mem[i][0] = nums[i] * mem[i-1][0]; + } + + for (int i = nums.length - 1; i >= 0; i--) { // O(N) + if (i == nums.length - 1) { + mem[i][1] = nums[i]; + continue; + } + mem[i][1] = nums[i] * mem[i+1][1]; + } + + int[] ret = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { // O(N) + int left = (i - 1) >= 0 ? mem[i-1][0] : 1; + int right = (i + 1) < nums.length ? mem[i+1][1] : 1; + ret[i] = left * right; + } + + return ret; + } +} + diff --git a/product-of-array-except-self/HodaeSsi.py b/product-of-array-except-self/HodaeSsi.py new file mode 100644 index 000000000..c77f6bc7e --- /dev/null +++ b/product-of-array-except-self/HodaeSsi.py @@ -0,0 +1,30 @@ +# 시간복잡도: O(n) +# 공간복잡도: O(n) +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + prefix = [1] * len(nums) + suffix = [1] * len(nums) + product = [1] * len(nums) + + for idx in range(len(nums)): + if idx == 0: + prefix[idx] = nums[idx] + else: + prefix[idx] = prefix[idx - 1] * nums[idx] + + for idx in range(len(nums) - 1, -1, -1): + if idx == len(nums) - 1: + suffix[idx] = nums[idx] + else: + suffix[idx] = suffix[idx + 1] * nums[idx] + + for idx in range(len(nums)): + if idx == 0: + product[idx] = suffix[idx + 1] + elif idx == len(nums) - 1: + product[idx] = prefix[idx - 1] + else: + product[idx] = prefix[idx - 1] * suffix[idx + 1] + + return product + diff --git a/product-of-array-except-self/Jeehay28.js b/product-of-array-except-self/Jeehay28.js new file mode 100644 index 000000000..0672ca6d2 --- /dev/null +++ b/product-of-array-except-self/Jeehay28.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ + +// Time Complexity: O(n) +// Space Complexity: O(n) +var productExceptSelf = function (nums) { + + let result = []; + + let left = Array(nums.length).fill(1) + let right = Array(nums.length).fill(1) + + for (let i = 1; i < nums.length; i++) { + + left[i] = left[i - 1] * nums[i - 1]; + right[nums.length - 1 - i] = right[right.length - i] * nums[nums.length - i] + + } + + for (let i = 0; i < nums.length; i++) { + result[i] = left[i] * right[i]; + } + + return result; + + +}; + diff --git a/product-of-array-except-self/KwonNayeon.py b/product-of-array-except-self/KwonNayeon.py new file mode 100644 index 000000000..1ac91388e --- /dev/null +++ b/product-of-array-except-self/KwonNayeon.py @@ -0,0 +1,38 @@ +""" +Constraints: + 1. 2 <= nums.length <= 10^5 + 2. -30 <= nums[i] <= 30 + 3. The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer + +Time Complexity: O(n) + - 배열을 두 번 순회하므로 O(n) + +Space Complexity: O(1) + - 출력 배열(answer)을 제외하면 추가 공간이 상수만큼만 필요(left, right 변수) + +풀이 방법: + 1. answer 배열을 1로 초기화 (곱셈에서는 1이 영향을 주지 않음) + 2. 왼쪽에서 오른쪽으로 순회: + - answer[i]에 현재까지의 left 누적값을 곱함 + - left *= nums[i]로 다음을 위해 left 값을 업데이트 + 3. 오른쪽에서 왼쪽으로 순회 (range(n-1, -1, -1) 사용): + - answer[i]에 현재까지의 right 누적값을 곱함 + - right *= nums[i]로 다음을 위해 right 값을 업데이트 +""" + +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(nums) + answer = [1] * n + + left = 1 + for i in range(n): + answer[i] *= left + left *= nums[i] + + right = 1 + for i in range(n-1, -1, -1): + answer[i] *= right + right *= nums[i] + + return answer diff --git a/product-of-array-except-self/Real-Reason.kt b/product-of-array-except-self/Real-Reason.kt new file mode 100644 index 000000000..039f93356 --- /dev/null +++ b/product-of-array-except-self/Real-Reason.kt @@ -0,0 +1,29 @@ +package leetcode_study + +fun productExceptSelf(nums: IntArray): IntArray { + // ex. nums = [1, 2, 3, 4] + val leftStartProducts = mutableListOf(1) + val rightStartProducts = mutableListOf(1) + + // mutableNums = [1, 1, 2, 3, 4] + val mutableNums = nums.toMutableList() + mutableNums.add(0, 1) + mutableNums.add(1) + + // leftStartProducts = [1, 1, 2, 6, 24, 24] + // rightStartProducts = [24, 24, 24, 12, 4, 1] + for (idx in 1..< mutableNums.size) { + val leftNum = mutableNums[idx] + val rightNum = mutableNums[mutableNums.size - 1 - idx] + + leftStartProducts.add(leftStartProducts.last() * leftNum) + rightStartProducts.add(index = 0, element = rightStartProducts.first() * rightNum) + } + + val result = mutableListOf() + for (idx in 0..mutableNums.size - 3) { + result.add(leftStartProducts[idx] * rightStartProducts[idx + 2]) + } + + return result.toIntArray() +} diff --git a/product-of-array-except-self/YeomChaeeun.ts b/product-of-array-except-self/YeomChaeeun.ts new file mode 100644 index 000000000..43f5e6ad7 --- /dev/null +++ b/product-of-array-except-self/YeomChaeeun.ts @@ -0,0 +1,47 @@ +/** + * 본인 인덱스에 있는 값을 제외한 모든 수의 곱 + * 알고리즘 복잡도 + * - 시간복잡도: O(n) + * - 공간복잡도: O(1) + * @param nums + */ +function productExceptSelf(nums: number[]): number[] { + let len = nums.length + let output = Array(len).fill(1) + + /* ex) [1, 2, 3, 4] + left >>> + i = 0 -> 1 = 1 + i = 1 -> 1 * 1 = 1 + i = 2 -> 1 * 1 * 2 = 2 + i = 3 -> 1 * 1 * 2 * 3 = 6 + */ + // 왼쪽부터 누적 곱 + let left = 1 + for (let i = 0; i < len; i++) { + output[i] *= left + left *= nums[i] + } + + /* + right >>> + i = 3 -> 1 = 1 + i = 2 -> 1 * 4 = 4 + i = 1 -> 1 * 4 * 3 = 12 + i = 3 -> 1 * 4 * 3 * 2 = 24 + + output >>> + i = 0 -> 1 * 24 = 24 + i = 1 -> 1 * 12 = 12 + i = 2 -> 2 * 4= 8 + i = 3 -> 6 * 1 = 6 + */ + // 오른쪽부터 누적 곱을 output 각 자리에 곱함 + let right = 1 + for (let i = len - 1; i >= 0; i--) { + output[i] *= right + right *= nums[i] + } + + return output +} diff --git a/product-of-array-except-self/Yjason-K.ts b/product-of-array-except-self/Yjason-K.ts new file mode 100644 index 000000000..50f99518d --- /dev/null +++ b/product-of-array-except-self/Yjason-K.ts @@ -0,0 +1,38 @@ +/** + * 주어진 배열에서 자신의 인덱스를 제외한 나머지 요소들의 곱을 계산하는 함수 + * + * @param {number[]} nums - 정수 배열 + * @returns {number[]} - 각 인덱스의 요소를 제외한 나머지 요소들의 곱을 구한 배열 + * + * 1. 결과 배열 `result`를 1로 초기화. + * 2. 왼쪽에서 오른쪽으로 순회하며 `left` 값을 이용해 기준 idx 이전의 값을 계산하여 `result`에 저장. + * 3. 오른쪽에서 왼쪽으로 순회하며 `right` 값을 이용해 접미 기준 idx 이후의 값들을 계산 히야 `result`에 곱함. + * 4. 결과 배열 `result`를 반환. + * + * 시간 복잡도: + * - 왼쪽에서 오른쪽 순회: O(n) + * - 오른쪽에서 왼쪽 순회: O(n) + * - 전체 시간 복잡도: O(n) + * + * 공간 복잡도: + * - 추가 배열 없이 상수 공간 사용 (result는 문제의 요구 조건에 포함되지 않음). + * - 전체 공간 복잡도: O(1) + */ +function productExceptSelf(nums: number[]): number[] { + const numLength = nums.length; + const result = new Array(numLength).fill(1); + + let left = 1; + for (let i = 0; i < numLength; i++) { + result[i] *= left; + left *= nums[i]; + } + + let right = 1; + for (let i = numLength; i >= 0; i--) { + result[i] *= right; + right *= nums[i]; + } + + return result; +} diff --git a/product-of-array-except-self/Zioq.js b/product-of-array-except-self/Zioq.js new file mode 100644 index 000000000..ccb304bbd --- /dev/null +++ b/product-of-array-except-self/Zioq.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var productExceptSelf = function(nums) { + let result = Array.from({length: nums.length}, () => 1) // Initialize return array + + // Iterate left to right + let left = 1; + for( let i =0 ; i=0; i-- ) { + result[i] *= right; + right *= nums[i]; + } + + // console.log(result) + return result +}; + +/* + Time Complexity: O(n): Loop the nth nums array length + Space Complexity: O(1) +*/ + + + +console.log(productExceptSelf([1,2,3,4])) +console.log(productExceptSelf([-1,1,0,-3,3])) + + diff --git a/product-of-array-except-self/aa601.py b/product-of-array-except-self/aa601.py new file mode 100644 index 000000000..cfd7ab4d9 --- /dev/null +++ b/product-of-array-except-self/aa601.py @@ -0,0 +1,17 @@ +#시간복잡도: O(n), 공간복잡도 : O(n) + +class Solution: + def productExceptSelf(self, nums: list[int]) -> list[int] : + a = [1] * len(nums) + for n in range(len(nums) - 1) : + a[n + 1] = a[n] * nums[n] + + b = [1] * len(nums) + for n in range(len(nums) - 1, 0, -1) : + b[n - 1] = b[n] * nums[n] + + c = [1] * len(nums) + for n in range(len(nums)) : + c[n] = a[n] * b[n] + return c + diff --git a/product-of-array-except-self/changchanghwang.go b/product-of-array-except-self/changchanghwang.go new file mode 100644 index 000000000..e6aaa51ac --- /dev/null +++ b/product-of-array-except-self/changchanghwang.go @@ -0,0 +1,26 @@ +// time complexity: O(n) +// space complexity: O(1) +// prefix와 postfix를 이용하여 계산 +// 예를 들어, [1, 2, 3, 4] 일 때, +// prefix는 [1, 1, 2, 6] 이고 postfix는 [24, 12, 4, 1] 이다. +// 그리고 서로 곱하면 [24, 12, 8, 6] 이 된다. +func productExceptSelf(nums []int) []int { + res := make([]int, len(nums)) + for i := range res { + res[i] = 1 + } + + prefix := 1 + for i := 0; i < len(nums); i++ { + res[i] = prefix + prefix *= nums[i] + } + + postfix := 1 + for i := len(nums) - 1; i >= 0; i-- { + res[i] *= postfix + postfix *= nums[i] + } + + return res +} diff --git a/product-of-array-except-self/dalpang81.java b/product-of-array-except-self/dalpang81.java new file mode 100644 index 000000000..9960f0570 --- /dev/null +++ b/product-of-array-except-self/dalpang81.java @@ -0,0 +1,23 @@ +/* +* 시간복잡도: O(n) +* 공간복잡도: O(1) +* */ +class Solution { + public int[] productExceptSelf(int[] nums) { + int n = nums.length; + int[] answer = new int[n]; + + answer[0] = 1; + for (int i = 1; i < n; i++) { + answer[i] = answer[i - 1] * nums[i - 1]; + } + + int suffixProduct = 1; + for (int i = n - 1; i >= 0; i--) { + answer[i] *= suffixProduct; + suffixProduct *= nums[i]; + } + + return answer; + } +} diff --git a/product-of-array-except-self/donghyeon95.java b/product-of-array-except-self/donghyeon95.java new file mode 100644 index 000000000..016c0b0aa --- /dev/null +++ b/product-of-array-except-self/donghyeon95.java @@ -0,0 +1,31 @@ +class Solution { + public int[] productExceptSelf(int[] nums) { + int[] result = new int[nums.length]; + int[] right = new int[nums.length]; + int[] left = new int[nums.length]; + + // -> 이쪽 방향으로 한번 계산 + right[0] = nums[0]; + for (int i=1; i-1; i--) { + left[i] = left[i+1]*nums[i]; + } + + // f(i) = right(i-1) * left(i+1) + result[0] = left[1]; + result[nums.length-1] = right[nums.length-2]; + for (int i=1; i List[int]: + n = len(nums) + answer = [1] * n + + # prefix + for i in range(1, n): + answer[i] *= nums[i - 1] * answer[i - 1] + + # suffix + suffix_product = 1 + for i in range(n - 1, -1, -1): + answer[i] *= suffix_product + suffix_product *= nums[i] + + return answer diff --git a/product-of-array-except-self/ekgns33.java b/product-of-array-except-self/ekgns33.java new file mode 100644 index 000000000..14e313f2a --- /dev/null +++ b/product-of-array-except-self/ekgns33.java @@ -0,0 +1,72 @@ +/* +input : array of integer +output : array of integer that each element + is product of all the elements except itself +constraint +1) is the result of product also in range of integer? +yes product of nums is guaranteed to fit 32-bit int +2) how about zero? +doesn't matter if the prduct result is zero +3) is input array non-empty? +yes. length of array is in range [2, 10^5] + +solution1) brute force + +calc all the product except current index element + +tc : O(n^2) sc : O(n) << for the result. when n is the length of input array + +solution 2) better? +ds : array +algo : hmmm we can reuse the product using prefix sum + +1) get prefix sum from left to right and vice versa : 2-O(n) loop + 2-O(n) space +2) for i = 0 to n-1 when n is the length of input + get product of leftPrfex[i-1] * rightPrefix[i+1] + // edge : i == 0, i == n-1 + +tc : O(n) sc : O(n) + +solution 3) optimal? +can we reduce space? +1) product of all elements. divide by current element. + + > edge : what if current element is zero? + 2) if there exists only one zero: + all the elements except zero index will be zero + 3) if there exist multiple zeros: + all the elements are zero + 4) if there is no zero + do 1) + */ +class Solution { + public int[] productExceptSelf(int[] nums) { + int n = nums.length, product = 1, zeroCount = 0; + for(int num : nums) { + if(num == 0) { + zeroCount ++; + if(zeroCount > 1) break; + } else { + product *= num; + } + } + + int[] answer = new int[n]; + if(zeroCount > 1) { + return answer; + } else if (zeroCount == 1) { + for(int i = 0; i < n; i++) { + if(nums[i] != 0) { + answer[i] = 0; + continue; + } + answer[i] = product; + } + } else { + for(int i = 0; i < n; i++) { + answer[i] = product / nums[i]; + } + } + return answer; + } +} diff --git a/product-of-array-except-self/eunhwa99.java b/product-of-array-except-self/eunhwa99.java new file mode 100644 index 000000000..975cc94ba --- /dev/null +++ b/product-of-array-except-self/eunhwa99.java @@ -0,0 +1,35 @@ +// 풀이 +// 현재 인덱스가 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]) + + +// DP 를 사용하면 시간 복잡도는 O(N) +// 공간 복잡도는 2개의 배열이 필요하고, 답으로 보낼 배열까지 해서 O(3*N) = O(N) + +class Solution { + public int[] productExceptSelf(int[] nums) { + int len = nums.length; + int[] leftProduct = new int[len]; + int[] rightProduct = new int[len]; + + 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]; + } + + 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; + } +} + diff --git a/product-of-array-except-self/forest000014.java b/product-of-array-except-self/forest000014.java new file mode 100644 index 000000000..c7cc473c6 --- /dev/null +++ b/product-of-array-except-self/forest000014.java @@ -0,0 +1,101 @@ +/* +runtime 8 ms, beats 4.87% +memory 55.44 MB, beats 54.17% + +time complexity: O(n) +- nums 각각의 원소를 소인수분해 : O(10 * n) = O(n) +- ans[] 배열 계산 : O(10 * n) + - i, j, k의 3중 for-loop가 O(n * 10 * 4) 처럼 보일 수 있는데요(10은 소인수 분해 base의 개수, 4는 power중 최대값), + - 실제로는 k가 큰 경우에는 j-loop가 일찍 끝나고 (예컨대 nums[i] = 2^4 인 경우에는, base가 2에서 끝나니 j-loop가 j=1에서 끝남) + - j가 큰 경우에는 k-loop가 일찍 끝나므로 (예컨대 num[i] = 29인 경우에는, k-loop가 1에서 끝남) + - 최악의 경우에 O(n * 10) 정도로 보는 게 타당하다고 생각합니다. + +space complexity: O(1) + +[풀이] +나눗셈이 금지되어 있기 때문에, 최대한 곱할 수 있는 만큼을 미리 곱해놓고, i번째 원소마다 부족한 부분만큼을 나중에 채워 넣어 곱해주는 방식으로 접근했습니다. +nums[i]의 절대값이 30 이하인 점에 착안해서, nums[i]는 많아야 10개의 base로 소인수 분해가 가능하다는 점을 떠올렸습니다. 따라서 각각의 base마다 (nums 전체에서 등장한 base의 지수의 총합) - (nums[i]의 base의 지수 중 가장 큰 값) 만큼의 지수로 미리 곱해주고, i에 대한 iteration에서 부족한 지수만큼을 보충해서 곱해주었습니다. +(풀이를 쓰다 보니, 실제 코드에서 이렇게 미리 곱해 놓은 수를 base라고 명명한 게 혼동될 수 있겠네요...^^;) + +이 풀이에서 아쉬운 점이 여전히 있습니다. 시간 복잡도를 따지면 O(10*n) = O(n)이니 문제의 조건을 맞췄다고 할 수도 있겠지만, 상수가 좀 크다는 점이 마음에 걸리네요. +(for (int j = 0; j < 10 && abs > 1; j++) <--- 여기에서 abs == 1이 되면 for-loop를 빠져나가게 했지만, nums[i]가 모두 29로 차있는 edge case라면 10*n을 꽉 채우게 되니까요.) +그래도 어쨌든 문제의 조건을 최대한 활용해서 시도해볼만한 접근이라고 생각합니다. + +이 풀이 말고도, nums[]를 2개로 나눈 블럭, 4개로 나눈 블럭, 8개로 나눈 블럭, ... 이런 식으로 사이즈 별로 블럭을 나눠두고, 각각의 블럭 내부의 곱을 미리 계산해두는 방식도 생각해보았습니다. 이러면 시간 복잡도와 공간 복잡도가 모두 O(nlogn)이 나올 것 같습니다. (사실 이 풀이를 가장 처음에 떠올렸습니다만, O(n)으로 줄이는 고민을 하다가 현재 제출한 풀이를 떠올리고서는 이 풀이는 구현을 안 했습니다. 시간이 되면 이렇게도 풀어보고, 좀 더 디벨롭을 해봐야겠네요.) +*/ +class Solution { + public int[] productExceptSelf(int[] nums) { + int n = nums.length; + + int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; + int[] sumPowers = new int[10]; + int[] maxPowers = new int[10]; + + int base = 1; + + int[] ans = new int[n]; + + for (int i = 0; i < n; i++) { + if (nums[i] == 0) { + int x = 1; + for (int j = 0; j < n; j++) { + if (j == i) { + continue; + } + ans[j] = 0; + x *= nums[j]; + } + ans[i] = x; + + return ans; + } + + int abs; + if (nums[i] > 0) { + abs = nums[i]; + } else { + abs = -nums[i]; + base = -base; + } + + for (int j = 0; j < 10 && abs > 1; j++) { + int curPower = 0; + while (abs % primes[j] == 0) { + sumPowers[j]++; + curPower++; + abs /= primes[j]; + } + if (curPower > maxPowers[j]) { + maxPowers[j] = curPower; + } + } + } + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < sumPowers[i] - maxPowers[i]; j++) { + base *= primes[i]; + } + } + + for (int i = 0; i < n; i++) { + ans[i] = base; + for (int j = 0; j < 10; j++) { + int tmp = nums[i]; + int power = 0; + while (tmp % primes[j] == 0) { + power++; + tmp /= primes[j]; + } + for (int k = 0; k < maxPowers[j] - power; k++) { + ans[i] *= primes[j]; + } + } + if (nums[i] < 0) { + ans[i] = -ans[i]; + } + } + + + return ans; + } +} diff --git a/product-of-array-except-self/gmlwls96.kt b/product-of-array-except-self/gmlwls96.kt new file mode 100644 index 000000000..21c2f227c --- /dev/null +++ b/product-of-array-except-self/gmlwls96.kt @@ -0,0 +1,20 @@ +class Solution { + // 시간 : O(2n) = O(n) ,공간 : O(1) + fun productExceptSelf(nums: IntArray): IntArray { + val answer = IntArray(nums.size) { 1 } + + var n = 1 + for (i in 0 until nums.lastIndex) { + n *= nums[i] + answer[i + 1] = n + } + println(answer.toList()) + + n = 1 + for (i in nums.lastIndex downTo 1) { + n *= nums[i] + answer[i - 1] *= n + } + return answer + } +} diff --git a/product-of-array-except-self/gwbaik9717.js b/product-of-array-except-self/gwbaik9717.js new file mode 100644 index 000000000..bc9a20eea --- /dev/null +++ b/product-of-array-except-self/gwbaik9717.js @@ -0,0 +1,24 @@ +// Time complexity: O(n) +// Space complexity: O(n) + +/** + * @param {number[]} nums + * @return {number[]} + */ +var productExceptSelf = function (nums) { + const n = nums.length; + const fromLeft = Array.from({ length: n + 1 }, () => 1); + const fromRight = Array.from({ length: n + 1 }, () => 1); + + for (let i = 1; i <= n; i++) { + fromLeft[i] = fromLeft[i - 1] * nums[i - 1]; + } + + for (let i = n - 1; i >= 0; i--) { + fromRight[i] = fromRight[i + 1] * nums[i]; + } + + return nums.map((num, i) => { + return fromLeft[i] * fromRight[i + 1]; + }); +}; diff --git a/product-of-array-except-self/heypaprika.py b/product-of-array-except-self/heypaprika.py new file mode 100644 index 000000000..ad5b88d83 --- /dev/null +++ b/product-of-array-except-self/heypaprika.py @@ -0,0 +1,36 @@ +""" +복잡도 : 예상 -> 예상한 이유 + +시간 복잡도 : O(n) -> for 문이 여러번 있지만, len(nums)만큼 여러번 반복하므로 O(n) +공간 복잡도 : O(n) -> len(nums)만큼의 배열 하나가 더 생기므로 +""" +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + zeros = 0 + products = 1 + ans_list = [0] * len(nums) + + for i in range(len(nums)): + if nums[i] == 0: + zeros += 1 + products *= nums[i] + + if zeros == 1: + products = 1 + alived_i = -1 + for i in range(len(nums)): + if nums[i] == 0: + alived_i = i + continue + products *= nums[i] + ans_list[alived_i] = products + return ans_list + elif zeros >= 2: + return ans_list + + ans_list = [products] * len(nums) + for i in range(len(nums)): + ans_list[i] //= nums[i] + + return ans_list + diff --git a/product-of-array-except-self/higeuni.js b/product-of-array-except-self/higeuni.js new file mode 100644 index 000000000..3c8a8417b --- /dev/null +++ b/product-of-array-except-self/higeuni.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number[]} + * + * Time Complexity: O(n) + * Space Complexity: O(n) + */ +var productExceptSelf = function(nums) { + const answer = [] + const zeros = nums.filter(n => n === 0).length; + if (zeros > 1) return new Array(nums.length).fill(0); + + const productOfNums = nums.reduce((acc, cur) => cur === 0 ? acc : acc * cur, 1); + + nums.forEach(num => { + if (num === 0) { + answer.push(productOfNums); + } else { + answer.push(zeros ? 0 : productOfNums / num); + } + }); + return answer +}; + diff --git a/product-of-array-except-self/imsosleepy.java b/product-of-array-except-self/imsosleepy.java new file mode 100644 index 000000000..9b7edc0f6 --- /dev/null +++ b/product-of-array-except-self/imsosleepy.java @@ -0,0 +1,20 @@ +class Solution { + // 누적곱을 이용한 풀이 int 크기를 보장해줘서 int를 사용하면된다. + // O(N)의 시간복잡도가 나온다. + public int[] productExceptSelf(int[] nums) { + int n = nums.length; + int[] result = new int[n]; + result[0] = 1; + for (int i = 1; i < n; i++) { + result[i] = result[i - 1] * nums[i - 1]; + } + + int right = 1; + for (int i = n - 1; i >= 0; i--) { + result[i] = result[i] * right; + right *= nums[i]; + } + + return result; + } +} diff --git a/product-of-array-except-self/jinah92.py b/product-of-array-except-self/jinah92.py new file mode 100644 index 000000000..68bb85e2b --- /dev/null +++ b/product-of-array-except-self/jinah92.py @@ -0,0 +1,21 @@ +# O(n) time, O(n) space +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + non_zero_product = math.prod(filter(lambda x: x != 0, nums)) + raw_product = math.prod(nums) + zero_total = nums.count(0) + + result = [] + + for num in nums: + if zero_total > 1: + result.append(0) + elif zero_total == 1: + if num == 0: + result.append(non_zero_product) + else: + result.append(raw_product) + else: + result.append(raw_product // num) + + return result diff --git a/product-of-array-except-self/limlimjo.js b/product-of-array-except-self/limlimjo.js new file mode 100644 index 000000000..8e8d7f806 --- /dev/null +++ b/product-of-array-except-self/limlimjo.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var productExceptSelf = function (nums) { + const result = new Array(nums.length).fill(1); // 결과값 + + // 왼쪽 곱 계산 + let leftProduct = 1; + for (let i = 0; i < nums.length; i++) { + result[i] = leftProduct; + leftProduct *= nums[i]; + } + + // 오른쪽 곱 계산해서 왼쪽 곱 계산한거 곱해주기 + let rightProduct = 1; + for (let i = nums.length - 1; i >= 0; i--) { + result[i] *= rightProduct; + rightProduct *= nums[i]; + } + + return result; +}; + +// 조건에 O(n)이라고 있음 +// 시간 복잡도: O(n) +// 공간 복잡도: O(n) diff --git a/product-of-array-except-self/mike2ox.ts b/product-of-array-except-self/mike2ox.ts new file mode 100644 index 000000000..4d01e4738 --- /dev/null +++ b/product-of-array-except-self/mike2ox.ts @@ -0,0 +1,25 @@ +/** + * source: https://leetcode.com/problems/product-of-array-except-self/ + * 풀이방법: 왼쪽부터의 누적 곱과 오른쪽부터의 누적 곱을 이용하여 결과 계산 + * 시간복잡도: O(n) (n: nums의 길이) + * 공간복잡도: O(1) (상수 공간만 사용) + */ +function productExceptSelf(nums: number[]): number[] { + const n = nums.length; + const result = new Array(n); + + // 왼쪽부터의 누적 곱 계산 + result[0] = 1; + for (let i = 1; i < n; i++) { + result[i] = result[i - 1] * nums[i - 1]; + } + + // 오른쪽부터의 누적 곱을 곱하면서 결과 계산 + let right = 1; + for (let i = n - 1; i >= 0; i--) { + result[i] = result[i] * right; + right *= nums[i]; + } + + return result; +} diff --git a/product-of-array-except-self/minji-go.java b/product-of-array-except-self/minji-go.java new file mode 100644 index 000000000..62d19204c --- /dev/null +++ b/product-of-array-except-self/minji-go.java @@ -0,0 +1,24 @@ +/* + Problem: https://leetcode.com/problems/product-of-array-except-self/ + Description: return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i]. + Concept: Array, Prefix Sum + Time Complexity: O(N), Runtime 5ms + Space Complexity: O(N), Memory 54.6MB - O(1) except the output array +*/ +class Solution { + public int[] productExceptSelf(int[] nums) { + int[] answer = new int[nums.length]; + Arrays.fill(answer, 1); + + int prefixProduct = 1; + int suffixProduct = 1; + for(int i=1; i= 0; i--) { + + answer[i] = answer[i] * value; + value *= nums[i]; + } + + return answer; + } +} diff --git a/product-of-array-except-self/mmyeon.ts b/product-of-array-except-self/mmyeon.ts new file mode 100644 index 000000000..3e1bae2a3 --- /dev/null +++ b/product-of-array-except-self/mmyeon.ts @@ -0,0 +1,31 @@ +/** + * + * 접근 방법 : + * - O(n)으로 풀어야 하니까 중첩이 아닌 배열 개별로 2번 순회 방법으로 접근 + * - 왼쪽 곱(prefixProduct)과 오른쪽 곱((suffixProduct)을 따로 계산해서 결과값에 저장 + * + * 시간복잡도 : O(n) + * - 배열 길이만큼 순회하니까 O(n) + * + * 공간복잡도 : O(n) + * - 배열 길이만큼 결과값 저장하니까 O(n) + * + */ + +function productExceptSelf(nums: number[]): number[] { + let result: number[] = Array(nums.length).fill(1); + let prefixProduct = 1; + let suffixProduct = 1; + + for (let i = 0; i < nums.length; i++) { + result[i] = prefixProduct; + prefixProduct *= nums[i]; + } + + for (let i = nums.length - 1; i >= 0; i--) { + result[i] *= suffixProduct; + suffixProduct *= nums[i]; + } + + return result; +} diff --git a/product-of-array-except-self/neverlish.go b/product-of-array-except-self/neverlish.go new file mode 100644 index 000000000..4d8f079c3 --- /dev/null +++ b/product-of-array-except-self/neverlish.go @@ -0,0 +1,69 @@ +// 시간복잡도 : O(n) +// 공간복잡도 : O(1) + +package main + +import "testing" + +func TestProductExceptSelf(t *testing.T) { + test1 := productExceptSelf([]int{1, 2, 3, 4}) + if len(test1) != 4 { + t.Errorf("Expected 4, got %d", len(test1)) + } + + if test1[0] != 24 && test1[1] != 12 && test1[2] != 8 && test1[3] != 6 { + t.Errorf("Expected [24, 12, 8, 6], got %v", test1) + } + + test2 := productExceptSelf([]int{0, 0}) + + if len(test2) != 2 { + t.Errorf("Expected 2, got %d", len(test2)) + } + + if test2[0] != 0 && test2[1] != 0 { + t.Errorf("Expected [0, 0], got %v", test2) + } + + test3 := productExceptSelf([]int{-1,1,0,-3,3}) + if len(test3) != 5 { + t.Errorf("Expected 5, got %d", len(test3)) + } + + if test3[0] != 0 && test3[1] != 0 && test3[2] != 9 && test3[3] != 0 && test3[4] != 0 { + t.Errorf("Expected [0, 0, 9, 0, 0], got %v", test3) + } +} + +func productExceptSelf(nums []int) []int { + zeroCount := 0 + product := 1 + + for _, num := range nums { + if num == 0 { + zeroCount++ + } else { + product *= num + } + } + + result := make([]int, len(nums)) + + if zeroCount > 1 { + return result + } + + for i, num := range nums { + if zeroCount == 1 { + if num == 0 { + result[i] = product + } else { + result[i] = 0 + } + } else { + result[i] = product / num + } + } + + return result +} diff --git a/product-of-array-except-self/pmjuu.py b/product-of-array-except-self/pmjuu.py new file mode 100644 index 000000000..0b8fb15ee --- /dev/null +++ b/product-of-array-except-self/pmjuu.py @@ -0,0 +1,27 @@ +from typing import List + + +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(nums) + result = [1] * n + + prefix = 1 + for i in range(n): + result[i] *= prefix + prefix *= nums[i] + + suffix = 1 + for i in range(-1, -n-1, -1): + result[i] *= suffix + suffix *= nums[i] + + return result + + +# 시간 복잡도: O(n) +# - 입력 배열 nums를 두 번 순회합니다. +# +# 공간 복잡도: O(1) +# - 추가 공간으로 사용하는 변수는 prefix와 suffix뿐이며, +# 출력 배열(result)은 추가 공간으로 계산하지 않습니다. diff --git a/product-of-array-except-self/sungjinwi.py b/product-of-array-except-self/sungjinwi.py new file mode 100644 index 000000000..89d4372b5 --- /dev/null +++ b/product-of-array-except-self/sungjinwi.py @@ -0,0 +1,18 @@ +""" + TC : for문 두번 반복하므로 O(2N) + -> O(N) + SC : answer 배열 외에 추가적인 메모리는 factor 변수 하나이므로 + -> O(1) +""" +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + answer = [1] * len(nums) + factor = 1 + for i in range(len(nums) - 1) : + factor *= nums[i] + answer[i + 1] *= factor + factor = 1 + for i in range(len(nums) - 1, 0, -1) : + factor *= nums[i] + answer[i - 1] *= factor + return answer diff --git a/product-of-array-except-self/taewanseoul.ts b/product-of-array-except-self/taewanseoul.ts new file mode 100644 index 000000000..8aba4f739 --- /dev/null +++ b/product-of-array-except-self/taewanseoul.ts @@ -0,0 +1,28 @@ +/** + * 238. Product of Array Except Self + * Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i]. + * The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer. + * You must write an algorithm that runs in O(n) time and without using the division operation. + * + * https://leetcode.com/problems/product-of-array-except-self/description/ + */ + +// O(n) time +// O(1) space +function productExceptSelf(nums: number[]): number[] { + const result = new Array(nums.length).fill(1); + + let left = 1; + for (let i = 0; i < nums.length - 1; i++) { + left *= nums[i]; + result[i + 1] *= left; + } + + let right = 1; + for (let i = nums.length - 1; i > 0; i--) { + right *= nums[i]; + result[i - 1] *= right; + } + + return result; +} diff --git a/product-of-array-except-self/thispath98.py b/product-of-array-except-self/thispath98.py new file mode 100644 index 000000000..c74d6616a --- /dev/null +++ b/product-of-array-except-self/thispath98.py @@ -0,0 +1,35 @@ +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + """ + Intuition: + i번째 인덱스의 값을 계산하기 위해서는 + 0 ~ i-1 까지의 값과 i+1 ~ N 까지의 값을 모두 곱해야 한다. + 이의 누적곱을 저장하여, 계산한다. + + Time Complexity: + O(N): + 리스트를 1번 순회하며 답을 찾으므로, + O(N)의 시간복잡도가 소요된다. + + Space Complexity: + O(N): + forward 배열과 backward 배열에 N개의 원소를 저장하므로 + O(N)의 공간복잡도가 소요된다. + + Key takeaway: + 스캔하여 값을 저장해두는 방식을 숙지하자. + """ + for_val = 1 + back_val = 1 + forward = [] + backward = [] + for i in range(len(nums)): + forward.append(for_val) + backward.append(back_val) + + for_val *= nums[i] + back_val *= nums[-(i + 1)] + backward = backward[::-1] + + answer = [forward[i] * backward[i] for i in range(len(nums))] + return answer diff --git a/reverse-bits/EcoFriendlyAppleSu.kt b/reverse-bits/EcoFriendlyAppleSu.kt new file mode 100644 index 000000000..0e0a45dc0 --- /dev/null +++ b/reverse-bits/EcoFriendlyAppleSu.kt @@ -0,0 +1,50 @@ +package leetcode_study + +/* +* 주어진 32 bits unsigned integer를 뒤집는 문제 +* Bit 연산에 대한 개념이 전무해 String으로 치환 후 문제 해결 +* 작은 수는 표현할 수 있었지만 아래와 같이 문제를 해결할 경우 큰 수가 입력되었을 경우 부호 비트를 인식하여 음수로 표기합니다. +* 또한 32 bit를 구성하기 위해 부족한 문자열을(자릿수) 추가하기 때문에 연산이 더해집니다. +* */ +fun reverseBits1(n:Int):Int { + val nStr = n.toString(2) + val totalLength = nStr.length + var temp = "" + if (totalLength != 32) { + for (i in 0 until 32 - totalLength) { + temp += "0" + } + } + val fullBitString = temp + nStr + var result = 0 + + for (i in (fullBitString.length - 1) downTo 0) { + val eachBitValue = 2.0.pow(i).toInt() + if (fullBitString[i] == '0') { + continue + } else { + result += eachBitValue + } + } + println(result.toString(2)) + return result +} + +/* +* Bit 연산을 통한 Reverse Bit 구성 +* 시간 복잡도: O(32) (32비트의 숫자에 대해 반복) +* 공간 복잡도: O(1) (상수 공간 사용) +* */ +fun reverseBits(n: Int): Int { + var input = n + var result = 0 + + for (i in 0 until 32) { + // 결과에 현재 비트 추가 + result = (result shl 1) or (input and 1) + // 입력 비트를 오른쪽으로 이동 + input = input shr 1 + } + + return result +} diff --git a/reverse-bits/GangBean.java b/reverse-bits/GangBean.java new file mode 100644 index 000000000..93f7ad6c1 --- /dev/null +++ b/reverse-bits/GangBean.java @@ -0,0 +1,24 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + /** + 1. understanding + - return the reversed 32 bit input num + 2. strategy + - assign stack + - iterate until stack.size is 32 + - push value % 2, and value /= 2 + 3. complexity + - time: O(1) + - space: O(1) + */ + int reversed = 0; + for (int i = 0; i < 32; i++) { + reversed <<= 1; + reversed |= n & 1; + n >>= 1; + } + return reversed; + } +} + diff --git a/reverse-bits/HodaeSsi.py b/reverse-bits/HodaeSsi.py new file mode 100644 index 000000000..6b67b91e2 --- /dev/null +++ b/reverse-bits/HodaeSsi.py @@ -0,0 +1,5 @@ +# 시간복잡도: O(1) (32bit) +class Solution: + def reverseBits(self, n: int) -> int: + return int(bin(n)[2:].zfill(32)[::-1], 2) + diff --git a/reverse-bits/Jeehay28.js b/reverse-bits/Jeehay28.js new file mode 100644 index 000000000..4e9330264 --- /dev/null +++ b/reverse-bits/Jeehay28.js @@ -0,0 +1,35 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ + +// Time Complexity: O(1) +// Space Complexity: O(1) + +var reverseBits = function (n) { + + let stack = []; + let num = n; + + for (let i = 0; i < 32; i++) { + + stack.push(num % 2); + num = Math.floor(num / 2); + } + + stack = stack.reverse(); + + + let result = 0; + + for (let i = 0; i < 32; i++) { + + result += stack[i] * Math.pow(2, i); + + } + + return result; + +}; + + diff --git a/reverse-bits/KwonNayeon.py b/reverse-bits/KwonNayeon.py new file mode 100644 index 000000000..838ff907d --- /dev/null +++ b/reverse-bits/KwonNayeon.py @@ -0,0 +1,24 @@ +""" +Constraints: + - The input must be a binary string of length 32 + +Time Complexity: O(1) + - 항상 고정된 32비트 문자열에 대해 연산하므로 상수 시간 + +Space Complexity: O(1) + - 32비트 고정 크기의 문자열 연산만 사용하므로 상수 공간 + +풀이 방법: + 1. format(n, '032b')를 사용해 입력받은 정수를 32비트 이진수 문자열로 변환함 + 2. 문자열 슬라이싱 [::-1]으로 비트를 뒤집음 + 3. int(reversed_binary, 2)로 뒤집은 이진수 문자열을 다시 정수로 변환함 +""" + +class Solution: + def reverseBits(self, n: int) -> int: + + binary = format(n, '032b') + + reversed_binary = binary[::-1] + + return int(reversed_binary, 2) diff --git a/reverse-bits/YeomChaeeun.ts b/reverse-bits/YeomChaeeun.ts new file mode 100644 index 000000000..70d7647ec --- /dev/null +++ b/reverse-bits/YeomChaeeun.ts @@ -0,0 +1,20 @@ +/** + * 정수를 비트로 변환후 뒤집어서 다시 정수로 반환 + * 알고리즘 복잡도 + * - 시간복잡도: O(1) + * - 공간복잡도: O(1) + * @param n + */ +function reverseBits(n: number): number { + // 2진수 배열로 변환 + let arr = n.toString(2).split('') + let len = arr.length + // 32비트 정렬 - 부족한 앞쪽에 0으로 채움 + for (let i = 0; i < (32 - len); i++) { + arr.unshift('0'); + } + // 뒤집은 후 합침 + let result = arr.reverse().join('') + // 2진수 정수로 변환하여 반환 + return parseInt(result,2) +} diff --git a/reverse-bits/Yjason-K.ts b/reverse-bits/Yjason-K.ts new file mode 100644 index 000000000..ff3cbb641 --- /dev/null +++ b/reverse-bits/Yjason-K.ts @@ -0,0 +1,22 @@ +/** + * 주어진 정수를 32비트로 변환하고 반전시켜 그때의 정수를 반환하는 문제. + * + * @param {number} n - 정수 (32비트)) + * @returns {number} - 2진수 변환 및 반전하여 정수 변환. + * + * 내장 메서드를 사용하여 32비트 2진수 변환 후, reverse하여 다시 정수로 변환. + * + * 시간 복잡도: O(32) + * - 32비트 정수의 비트를 처리하므로 고정된 상수 시간. + * + * 공간 복잡도: O(32) + * - 2진수 문자열을 생성하고 반전된 문자열을 저장하므로 고정된 크기의 추가 메모리가 필요. + */ +function reverseBits(n: number): number { + // 숫자를 32비트 2진수 문자열로 변환 (앞에 0 채우기) + const binaryStr = n.toString(2).padStart(32, '0'); + // 2진수 문자열을 뒤집기 + const reversedBinaryStr = binaryStr.split('').reverse().join(''); + // 뒤집힌 2진수 문자열을 다시 숫자로 변환 + return parseInt(reversedBinaryStr, 2); +}; diff --git a/reverse-bits/Zioq.js b/reverse-bits/Zioq.js new file mode 100644 index 000000000..20f3d5ae6 --- /dev/null +++ b/reverse-bits/Zioq.js @@ -0,0 +1,19 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function(n) { + let result = 0; //Initial value + for (let i=0; i < 32; i++) { //The loop iterates 32 times, as the input n is a 32-bit unsigned integer + result = (result << 1) | (n & 1); // Shift the result to the left by 1 bit OR it with the least significant bit of n. + n >>= 1; // Shifts the bits of n one place to the right, effectively "removing" the processed LSB. + } + return result >>> 0; +}; +/* + Time Complexity: O(1), because we always loop exactly 32 times, regardless of the input. + Space Complexity: O(1), because we use a constant amount of space. +*/ + + + diff --git a/reverse-bits/aa601.py b/reverse-bits/aa601.py new file mode 100644 index 000000000..adb619f25 --- /dev/null +++ b/reverse-bits/aa601.py @@ -0,0 +1,10 @@ +#시간복잡도 : O(1), 공간복잡도 : O(1) + +class Solution: + def reverseBits(self, n: int) -> int: + ret = 0 + for i in range(32) : + ret = (ret << 1 | (n & 1)) + n >>= 1 + return (ret) + diff --git a/reverse-bits/anniemon.js b/reverse-bits/anniemon.js new file mode 100644 index 000000000..e410af501 --- /dev/null +++ b/reverse-bits/anniemon.js @@ -0,0 +1,20 @@ +/** + * 시간 복잡도: 상수(32)번 반복이 일어나므로 O(1) + * 공간 복잡도: 상수(32) 크기의 배열을 생성하므로 O(1) + */ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function(n) { + let i = 0; + let arr = []; + while(i < 32) { + arr.push(n % 2); + n = Math.floor(n / 2); + i++; + } + const bi = arr.reverse().join(''); + const reversedBi = bi.split('').reverse().join(''); + return parseInt(reversedBi, 2); +}; diff --git a/reverse-bits/changchanghwang.go b/reverse-bits/changchanghwang.go new file mode 100644 index 000000000..9f604dae2 --- /dev/null +++ b/reverse-bits/changchanghwang.go @@ -0,0 +1,6 @@ +// Time Complexity: O(1) +// Space Complexity: O(1) +func reverseBits(num uint32) uint32 { + reversedBits := bits.Reverse32(num) + return reversedBits +} diff --git a/reverse-bits/dalpang81.java b/reverse-bits/dalpang81.java new file mode 100644 index 000000000..99050b039 --- /dev/null +++ b/reverse-bits/dalpang81.java @@ -0,0 +1,16 @@ +/* +* 시간복잡도: O(1) +* 공간복잡도: O(1) +* */ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int result = 0; + for (int i = 0; i < 32; i++) { + result <<= 1; + result |= (n & 1); + n >>= 1; + } + return result; + } +} diff --git a/reverse-bits/donghyeon95.java b/reverse-bits/donghyeon95.java new file mode 100644 index 000000000..41c84f513 --- /dev/null +++ b/reverse-bits/donghyeon95.java @@ -0,0 +1,16 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int result = 0; + + for (int i = 0; i < 32; i++) { + // 왼쪽으로 비트를 한 칸 이동하고, n의 마지막 비트를 추가 + result = (result << 1) | (n & 1); + // n을 오른쪽으로 한 칸 이동 + n >>= 1; + } + + return result; + } +} + diff --git a/reverse-bits/dusunax.py b/reverse-bits/dusunax.py new file mode 100644 index 000000000..808d3efe4 --- /dev/null +++ b/reverse-bits/dusunax.py @@ -0,0 +1,41 @@ +''' +# 190. Reverse Bits + +SolutionA: using bin() and int() to convert the types. +SolutionB: using bitwise operations to reverse the bits. + +## Time and Space Complexity + +### SolutionA +``` +TC: O(32) -> O(1) +SC: O(1) +``` + +### SolutionB +``` +TC: O(32) -> O(1) +SC: O(1) +``` +''' +class Solution: + ''' + SolutionA + - using bin() and int() to convert the number to binary and back to integer. + - use .zfill(32) ensures that the binary string is always 32 bits long. + ''' + def reverseBitsA(self, n: int) -> int: + bit = bin(n)[2:].zfill(32) + return int(bit[::-1], 2) + + ''' + SolutionB + - using bitwise operations to reverse the bits. + - iterate through the bits and reverse them. + ''' + def reverseBitsB(self, n: int) -> int: + result = 0 + for i in range(32): + result = (result << 1) | (n & 1) # shift the result to the left & add LSB of n + n >>= 1 # shift n to the right & remove previous LSB + return result diff --git a/reverse-bits/easyone-jwlee.go b/reverse-bits/easyone-jwlee.go new file mode 100644 index 000000000..506482548 --- /dev/null +++ b/reverse-bits/easyone-jwlee.go @@ -0,0 +1,20 @@ +// 풀이 +// result 가장 오른쪽 값에 num의 값을 추가하면서 왼쪽으로 밀어 reverse 처리. + +// TC +// for문은 무조건 32회만 돌기때문에 O(1) + +// SC +// 추가적인 공간 사용량은 일정하므로 0(1) + +func reverseBits(num uint32) uint32 { + result := uint32(0) + for i := 0; i < 32; i++ { + result <<= 1 + if num%2 == 1 { + result++ + } + num >>= 1 + } + return result +} diff --git a/reverse-bits/ekgns33.java b/reverse-bits/ekgns33.java new file mode 100644 index 000000000..b78c5b73e --- /dev/null +++ b/reverse-bits/ekgns33.java @@ -0,0 +1,39 @@ +/* +input : 32 bit unsigned integer n +output : unsigned integer representation of reversed bit +constraint : +1) input is always 32 bit unsigned integer +2) implementation should not be affected by programming language + +solution 1) + +get unsigned integer bit representation + +build string s O(n) +reverse O(n) +get integer O(n) + +tc : O(n) sc : O(n) + +solution 2) one loop + +nth bit indicates (1<> 1) +// 최종 결과를 위한 값은 result에 저장할 예정이다. result의 경우, n과 반대로 왼쪽으로 한 칸씩 미루면서 n의 비트를 삽입해줘야 함 (OR 연산) + +// 시간 복잡도 (숫자의 비트 수 만큼 필요) -> O(N) (N: 숫자 n의 비트 수, 문제에서는 32로 고정) +// 공간 복잡도: (result 변수 크기) +public class Solution { + + public int reverseBits(int n) { + int result = 0; + for (int i = 0; i < 32; i++) { + result = result << 1; + result |= (n & 1); + n = n >> 1; + } + return result; + } +} + diff --git a/reverse-bits/forest000014.java b/reverse-bits/forest000014.java new file mode 100644 index 000000000..c7e6818e8 --- /dev/null +++ b/reverse-bits/forest000014.java @@ -0,0 +1,24 @@ +/* +runtime 0 ms, beats 100.00% +memory 41.47 MB, beats 90.14% + +time complexity: O(1) +space complexity: O(1) + +i번째 bit를 구하고, 이를 ans(초기값 0)의 31-i번째 자리에 bitwise-OR 연산을 하여, bit 위치를 reverse 했습니다. +*/ + +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int x = 1; + int ans = 0; + for (int i = 0; i < 32; i++) { + int bit = (x & n) >>> i; + bit <<= (31 - i); + ans |= bit; + x <<= 1; + } + return ans; + } +} diff --git a/reverse-bits/gmlwls96.kt b/reverse-bits/gmlwls96.kt new file mode 100644 index 000000000..7f12a7552 --- /dev/null +++ b/reverse-bits/gmlwls96.kt @@ -0,0 +1,14 @@ +class Solution { + // you need treat n as an unsigned value + fun reverseBits(n: Int): Int { + var bitString = Integer.toBinaryString(n) + bitString = CharArray(32 - bitString.length) { '0' }.concatToString() + bitString + var result = 0 + var scale = 1 + bitString.forEach { + result += it.digitToInt() * scale + scale *= 2 + } + return result + } +} diff --git a/reverse-bits/gwbaik9717.js b/reverse-bits/gwbaik9717.js new file mode 100644 index 000000000..723e629df --- /dev/null +++ b/reverse-bits/gwbaik9717.js @@ -0,0 +1,25 @@ +// Time complexity: O(1) +// Space complexity: O(1) + +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function (n) { + const stack = []; + let current = n; + + for (let i = 0; i < 32; i++) { + stack.push(current % 2); + current = Math.floor(current / 2); + } + + let answer = 0; + + for (let i = 0; i < 32; i++) { + const popped = stack.pop(); + answer += popped * 2 ** i; + } + + return answer; +}; diff --git a/reverse-bits/heypaprika.py b/reverse-bits/heypaprika.py new file mode 100644 index 000000000..cfbf85100 --- /dev/null +++ b/reverse-bits/heypaprika.py @@ -0,0 +1,15 @@ +""" +복잡도 : 예상 -> 예상한 이유 + +시간 복잡도 : O(1) -> 어떤 수가 들어오더라도 상수만큼 연산 +공간 복잡도 : O(1) -> 어떤 수가 들어오더라도 상수만큼 할당 +""" +class Solution: + def reverseBits(self, n: int) -> int: + ans = 0 + for i in range(32): + if n % 2 == 1: + ans += 2**(31-i) + n = n // 2 + return ans + diff --git a/reverse-bits/higeuni.js b/reverse-bits/higeuni.js new file mode 100644 index 000000000..51cb54c04 --- /dev/null +++ b/reverse-bits/higeuni.js @@ -0,0 +1,36 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + * + * Time Complexity: O(n)? n이 32이기 때문에 O(1)? + * Space Complexity: O(1) + */ + +// 일반적인 풀이 +var reverseBits = function(n) { + const binary = n.toString(2); + const reversedBinary = binary.split('').reverse().join('').padEnd(32, '0'); + const answer = parseInt(reversedBinary, 2); + + return answer; + // return parseInt(n.toString(2).split('').reverse().join('').padEnd(32, '0'), 2); +}; + +/** + * + * Time Complexity: O(1) + * Space Complexity: O(1) +*/ + +// 비트 연산을 이용한 풀이 +var reverseBits2 = function(n) { + let result = 0; + for(let i = 0; i < 32; i++) { + // result를 왼쪽으로 시프트하고 n의 마지막 비트를 더함 + result = (result << 1) | (n & 1); + // n을 오른쪽으로 시프트 + n = n >> 1; + } + return result >>> 0; +} + diff --git a/reverse-bits/imsosleepy.java b/reverse-bits/imsosleepy.java new file mode 100644 index 000000000..38f272bb5 --- /dev/null +++ b/reverse-bits/imsosleepy.java @@ -0,0 +1,23 @@ +// 스택으로 풀기보다 비트연산자로 풀이 +// 스택을 사용할 때는 32자리의 불필요한 공간이 생긴다. +public class Solution { + public int reverseBits(int n) { + // n 이 십진수로 들어온다.(중요) + int result = 0; + for (int i = 0; i < 32; i++) { + // 마지막 비트 확인 + // 홀수: 마지막 비트가 1 (n & 1 == 1) + // 짝수: 마지막 비트가 0 (n & 1 == 0) + int bit = n & 1; + // result를 왼쪽으로 1비트 이동하고, 추출한 비트를 추가 + // - result의 마지막 비트를 비우고 (<< 1) + // - OR 연산(|)으로 추출한 비트를 추가 + result = (result << 1) | bit; + + // n을 오른쪽으로 1비트 이동하여 다음 비트를 준비 + // - n의 마지막 비트를 버리고, 상위 비트를 아래로 이동 + n >>= 1; + } + return result; + } +} diff --git a/reverse-bits/jinah92.py b/reverse-bits/jinah92.py new file mode 100644 index 000000000..4d2d8cf5e --- /dev/null +++ b/reverse-bits/jinah92.py @@ -0,0 +1,14 @@ +# O(1) time, O(1) space +class Solution: + def reverseBits(self, n: int) -> int: + stack = [] + while len(stack) < 32: + stack.append(n % 2) + n //=2 + + result, scale = 0, 1 + while stack: + result += stack.pop() * scale + scale *= 2 + + return result diff --git a/reverse-bits/limlimjo.js b/reverse-bits/limlimjo.js new file mode 100644 index 000000000..d23ef8ba5 --- /dev/null +++ b/reverse-bits/limlimjo.js @@ -0,0 +1,29 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function (n) { + // 문자열로 변환 + let nString = n.toString(2).padStart(32, "0"); + //console.log(nString); + + // 스택 생성 (스택은 나중에 들어온게 먼저 나가므로) + let stack = []; + + // nString 스택에 넣기 + for (let i = 0; i < nString.length; i++) { + stack.push(nString[i]); + } + + // pop하여 뒤집힌 문자열 만들기 + let reverseNString = ""; + for (let i = 0; i < nString.length; i++) { + reverseNString += stack.pop(); + } + + // 뒤집힌 문자열을 정수로 변환 + return parseInt(reverseNString, 2); +}; + +// 시간 복잡도: O(1) +// 공간 복잡도: O(1) diff --git a/reverse-bits/mike2ox.ts b/reverse-bits/mike2ox.ts new file mode 100644 index 000000000..ef2524de9 --- /dev/null +++ b/reverse-bits/mike2ox.ts @@ -0,0 +1,16 @@ +/** + * source: https://leetcode.com/problems/reverse-bits/ + * 풀이방법: 비트 연산을 이용하여 뒤집기 + * 시간복잡도: O(1) + * 공간복잡도: O(1) + */ +function reverseBits(n: number): number { + let result = 0; + const bitSize = 32; + // 32비트를 순회하면서 뒤집기 + for (let i = 0; i < bitSize; i++) { + const bit = (n >> i) & 1; // i번째 비트 추출 + result = result | (bit << (bitSize - 1 - i)); // 뒤집은 비트를 result에 저장 + } + return result >>> 0; // 부호비트를 제거하기 위해 0으로 비트 이동 +} diff --git a/reverse-bits/minji-go.java b/reverse-bits/minji-go.java new file mode 100644 index 000000000..de134e9db --- /dev/null +++ b/reverse-bits/minji-go.java @@ -0,0 +1,19 @@ +/* + Problem: https://leetcode.com/problems/reverse-bits/ + Description: Reverse bits of a given 32 bits unsigned integer + Topics: Divide and Conquer, Bit Manipulation + Time Complexity: O(1), Runtime 1ms + Space Complexity: O(1), Memory 41.72MB +*/ +public class Solution { + public int reverseBits(int n) { + long unsignedNum = n > 0 ? n : n + 2 * (long) Math.pow(2,31); //= Integer.toUnsignedLong() + + int reversedNum = 0; + for(int i=31; i>=0; i--){ + if(unsignedNum % 2 == 1) reversedNum += (long) Math.pow(2,i); //= (1< 루프는 항상 32번 반복되기 때문 + 공간복잡도: O(1) + */ + + // you need treat n as an unsigned value + public int reverseBits(int n) { + int answer = 0; + int index = 31; + + while(n != 0) { + // n&1 : 마지막 비트를 추출 + // << : 0을 패딩처리 시켜서 상위 자리수로 올려버림 + answer += (n & 1) << index; + + // >>> : 부호 상관없이 오른쪽으로 비트 이동 + n = n >>> 1; + index--; + } + + return answer; + } +} diff --git a/reverse-bits/neverlish.go b/reverse-bits/neverlish.go new file mode 100644 index 000000000..8405bd9be --- /dev/null +++ b/reverse-bits/neverlish.go @@ -0,0 +1,22 @@ +// 시간복잡도: O(1) +// 공간복잡도: O(1) + +package main + +func reverseBits(num uint32) uint32 { + stack := []uint32{} + + for i := 0; i < 32; i++ { + stack = append(stack, num&1) + num >>= 1 + } + + result := uint32(0) + + for i := 0; i < 32; i++ { + result <<= 1 + result |= stack[i] + } + + return result +} diff --git a/reverse-bits/pmjuu.py b/reverse-bits/pmjuu.py new file mode 100644 index 000000000..cd8d240aa --- /dev/null +++ b/reverse-bits/pmjuu.py @@ -0,0 +1,42 @@ +class Solution: + def reverseBits(self, n: int) -> int: + # 이진수로 변환한 후 '0b' 제거 + binary = bin(n)[2:] + # 32비트 길이에 맞게 앞쪽에 0을 채움 + binary = binary.zfill(32) + # 이진수를 뒤집음 + reversed_binary = binary[::-1] + # 뒤집힌 이진수를 정수로 변환하여 반환 + return int(reversed_binary, 2) + + +# 시간 복잡도: O(32) +# - bin(): O(32) +# - zfill(32): O(32) +# - 문자열 뒤집기 [::-1]: O(32) +# - int(문자열, 2): O(32) +# 총합: O(32) (상수 시간으로 간주 가능) + +# 공간 복잡도: O(32) +# - 이진 문자열(binary)와 뒤집힌 문자열(reversed_binary)을 저장하므로 O(32). + + +class Solution: + def reverseBits(self, n: int) -> int: + result = 0 + + for i in range(32): + # result를 왼쪽으로 1비트 이동하고 n의 마지막 비트를 추가 + result = (result << 1) | n & 1 + # n을 오른쪽으로 1비트 이동 + n >>= 1 + + return result + + +# 시간 복잡도: O(32) +# - 반복문이 32번 실행되며 각 작업(비트 이동 및 OR 연산)은 O(1). +# 총합: O(32) (상수 시간으로 간주 가능) + +# 공간 복잡도: O(1) +# - 추가로 사용하는 변수 result와 n만 저장하므로 상수 공간. diff --git a/reverse-bits/river20s.java b/reverse-bits/river20s.java new file mode 100644 index 000000000..76a976fe9 --- /dev/null +++ b/reverse-bits/river20s.java @@ -0,0 +1,22 @@ +public class Solution { + /* T.C = O(1) + * S.C = O(1) + */ + public int reverseBits(int n) { + // Set the output to 0 + int output = 0; + // Repeat 32 times + for (int i = 0; i < 32; i++) { + // Shift the output value one space to the left to make room for the new bit + output <<= 1; + // '&' operation to get the rightmost bit and add it to the output + output = output | (n & 1); + // Discard the rightmost bit of the 'n' + n = n >> 1; + } + + return output; + + } +} + diff --git a/reverse-bits/sungjinwi.py b/reverse-bits/sungjinwi.py new file mode 100644 index 000000000..5bd2346d5 --- /dev/null +++ b/reverse-bits/sungjinwi.py @@ -0,0 +1,16 @@ +""" + TC : n의 크기에 상관없이 32번 반복하므로 + O(1) + SC : 추가적인 메모리 쓰지 않으므로 + O(1) +""" + +class Solution: + def reverseBits(self, n: int) -> int: + ret = 0 + for _ in range(31) : + ret |= n & 1 + ret <<= 1 + n >>= 1 + ret |= n & 1 + return ret diff --git a/reverse-bits/taewanseoul.ts b/reverse-bits/taewanseoul.ts new file mode 100644 index 000000000..eb454e1d1 --- /dev/null +++ b/reverse-bits/taewanseoul.ts @@ -0,0 +1,26 @@ +/** + * 190. Reverse Bits + * Reverse bits of a given 32 bits unsigned integer. + * + * https://leetcode.com/problems/reverse-bits/description/ + */ + +// O(1) time +// O(1) space +function reverseBits(n: number): number { + const bits: number[] = []; + + while (bits.length < 32) { + bits.push(n & 1); + n = n >> 1; + } + + let result = 0; + let scale = 1; + for (let i = bits.length - 1; i >= 0; i--) { + result += bits[i] * scale; + scale *= 2; + } + + return result; +} diff --git a/reverse-bits/thispath98.py b/reverse-bits/thispath98.py new file mode 100644 index 000000000..38be2e89a --- /dev/null +++ b/reverse-bits/thispath98.py @@ -0,0 +1,26 @@ +class Solution: + def reverseBits(self, n: int) -> int: + """ + Intuition: + 비트를 역순으로 순회한다. + answer에는 최대값(2^31)부터 최소값(2^0)으로 감소하는 + 방식으로 업데이트한다. + + Time Complexity: + O(N): + n을 1번 순회하며 답을 찾으므로, + O(N)의 시간복잡도가 소요된다. + + Space Complexity: + O(1): + answer에 값을 업데이트 하므로, 상수의 + 공간복잡도가 소요된다. + + Key takeaway: + 숫자를 binary string으로 만드는 bin() 메소드를 + 알게 되었다. + """ + answer = 0 + for i, bit in enumerate(bin(n)[2:][::-1]): + answer += int(bit) * 2 ** (31 - i) + return answer diff --git a/two-sum/EcoFriendlyAppleSu.kt b/two-sum/EcoFriendlyAppleSu.kt new file mode 100644 index 000000000..d980e8428 --- /dev/null +++ b/two-sum/EcoFriendlyAppleSu.kt @@ -0,0 +1,42 @@ +package leetcode_study + +/** + * 주어진 숫자 배열에서 두 개의 숫자를 더해 Target을 만들 수 있는 배열의 Index를 구하는 문제 + * 조합을 사용해 문제 해결 + * 시간 복잡도: O(n^2) + * -> 두 번의 순회를 통해 모든 경우의 수를 계산하는 경우 + * 공간 복잡도: O(1) + * -> 결과를 저장하는 result, 배열의 index를 가리키는 indices는 두 개의 값을 담기 때문에 O(1) + */ +fun twoSum(nums: IntArray, target: Int): IntArray { + val result = IntArray(2) + val k = 2 + val maxSize = nums.size + val indices = IntArray(k) + for (i in 0 until k ) { + indices[i] = i + } + + while (indices[k-1] < maxSize) { + if (nums[indices[0]] + nums[indices[1]] == target) { + result[0] = indices[0] + result[1] = indices[1] + return result + } + + var i = k - 1 + while (i >= 0 && indices[i] == i + maxSize - k) { + i-- + } + + if (i >= 0) { + indices[i]++ + for (j in i + 1 until k) { + indices[j] = indices[j - 1] + 1 + } + } else { + break + } + } + return result +} diff --git a/two-sum/GangBean.java b/two-sum/GangBean.java new file mode 100644 index 000000000..cd5abf382 --- /dev/null +++ b/two-sum/GangBean.java @@ -0,0 +1,35 @@ +class Solution { + public int[] twoSum(int[] nums, int target) { + /** + 1. understanding + - find the indices where the numbers of that index pair sum upto the target number. + - exactly one solution + - use each element only once + - return in any order + 2. strategy + - brute force: + - validate for all pair sum + - hashtable: + - assing hashtable variable to save the nums and index + - while iterate over the nums, + - calculate the diff, and check if the diff in the hashtable. + - or save new entry. + 3. complexity + - time: O(N) + - space: O(N) + */ + + Map map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + int diff = target - nums[i]; + if (map.containsKey(diff)) { + return new int[] {map.get(diff), i}; + } + map.put(nums[i], i); + } + + return new int[] {}; + } +} + diff --git a/two-sum/HerrineKim.js b/two-sum/HerrineKim.js new file mode 100644 index 000000000..595c2898b --- /dev/null +++ b/two-sum/HerrineKim.js @@ -0,0 +1,22 @@ +// 시간 복잡도 : O(n) +// 공간 복잡도 : O(n) + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + let numMap = new Map(); + + for (let i = 0; i < nums.length; i++) { + let complement = target - nums[i]; + + if (numMap.has(complement)) { + return [numMap.get(complement), i]; + } + + numMap.set(nums[i], i); + } +}; + diff --git a/two-sum/HodaeSsi.py b/two-sum/HodaeSsi.py new file mode 100644 index 000000000..0142a77e8 --- /dev/null +++ b/two-sum/HodaeSsi.py @@ -0,0 +1,13 @@ +# 시간복잡도 : O(n) +# 공간복잡도 : O(n) +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + seen = {} # {num: idx, ...} + + for i, num in enumerate(nums): + if target - num in seen: + return [seen[target - num], i] + seen[num] = i + + return [] + diff --git a/two-sum/Jeehay28.js b/two-sum/Jeehay28.js new file mode 100644 index 000000000..9b24e9073 --- /dev/null +++ b/two-sum/Jeehay28.js @@ -0,0 +1,49 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + + +// Time Complexity : O(n) +// Space Complexity : O(n) + +var twoSum = function (nums, target) { + + let map = new Map(); + + for (let i = 0; i < nums.length; i++) { + + const temp = target - nums[i]; + + if (map.has(temp)) { + return [i, map.get(temp)] + } + + map.set(nums[i], i); + } + + return []; +} + + +// Time Complexity: O(n^2) +// Space Complexity: O(1) +// This solution is straightforward but inefficient for large arrays. For better performance, consider the hashmap approach. + +// var twoSum = function (nums, target) { + +// for (let i = 0; i < nums.length; i++) { + +// const loc = nums.indexOf((target - nums[i]), i + 1); + +// if (loc >= 0) { +// return [i, loc] +// } else { +// continue; +// } + +// } + +// }; + diff --git a/two-sum/KwonNayeon.py b/two-sum/KwonNayeon.py new file mode 100644 index 000000000..969e83b72 --- /dev/null +++ b/two-sum/KwonNayeon.py @@ -0,0 +1,25 @@ +""" +Constraints: + - 2 <= nums.length <= 10^4 + - -10^9 <= nums[i] <= 10^9 + - -10^9 <= target <= 10^9 + - Only one valid answer exists. + +Time Complexity: O(n²) + - 중첩 반복문을 사용하기 때문 + - 첫 번째 반복문: n번 + - 각각에 대해 두 번째 반복문: n-1, n-2, ... 1번 + - 따라서 총 연산 횟수는 n * (n-1)/2로 O(n²) + +Space Complexity: O(1) + - 추가 공간을 사용하지 않음 + - result 리스트는 항상 크기가 2로 고정 +""" +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + result = [] + + for i in range(len(nums)): + for j in range(i+1, len(nums)): + if nums[j] == target - nums[i]: + return [i, j] diff --git a/two-sum/Real-Reason.kt b/two-sum/Real-Reason.kt new file mode 100644 index 000000000..84e1952f8 --- /dev/null +++ b/two-sum/Real-Reason.kt @@ -0,0 +1,16 @@ +package leetcode_study + +class `Real-Reason` { + fun twoSum(nums: IntArray, target: Int): IntArray { + for (startIdx in 0..< nums.size - 1) { + val firstNum = nums[startIdx] + for (endIdx in startIdx + 1..< nums.size) { + val secondNum = nums[endIdx] + if (target == firstNum + secondNum) { + return intArrayOf(startIdx, endIdx) + } + } + } + throw RuntimeException("There is no solution") + } +} diff --git a/two-sum/YeomChaeeun.ts b/two-sum/YeomChaeeun.ts new file mode 100644 index 000000000..977134d44 --- /dev/null +++ b/two-sum/YeomChaeeun.ts @@ -0,0 +1,20 @@ +/** + * 배열 두 수의 합이 target 과 같은 값 + * 알고리즘 복잡도: + * - 시간복잡도: O(n^2) + * - 공간복잡도: O(1) + * @param nums + * @param target + */ +function twoSum(nums: number[], target: number): number[] { + let result: number[] = []; + + for(let i = 0; i < nums.length; i++) { + for(let j = i + 1; j < nums.length; j++) { + if(nums[i] + nums[j] === target) { + result.push(i, j); + return result; + } + } + } +} diff --git a/two-sum/Yjason-K.ts b/two-sum/Yjason-K.ts new file mode 100644 index 000000000..daf78020b --- /dev/null +++ b/two-sum/Yjason-K.ts @@ -0,0 +1,25 @@ +/** + * 주어진 배열에서 두 숫자의 합이 target이 되는 idx 쌍을 반환하는 함수 + * - 시간 복잡도: O(n) + * - 한번의 배열을 순회하며 Map에 값을 저장하고, Map에서 값을 찾음 + * - 공간 복잡도: O(n) + * - 숫자와 그때의 idx를 쌍으로하는 Map + * + * @param {number[]} nums - 숫자 배열 + * @param {number} target - 타겟 합 + * @returns {number[]} - 합을 만들 수 있는 idx 배열 + */ +function twoSum(nums: number[], target: number): number[] { + const map = new Map(); + for (let i = 0; i < nums.length; i++) { + const cur = nums[i]; // 현재 값 + const reamin = target - cur; // 나머지 + if (map.has(reamin)) { + // Non-null assertion operator(!)를 사용하여 undefined가 아님을 단언 + return [map.get(reamin)!, i]; + } + // 나머지를 찾지 못한 경우 현재 값을 저장 + map.set(cur, i); + } + return []; // 목표 합을 만들 수 있는 숫자가 없는 경우 빈 배열 반환 +} diff --git a/two-sum/Zioq.js b/two-sum/Zioq.js new file mode 100644 index 000000000..592da9b53 --- /dev/null +++ b/two-sum/Zioq.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + // Initialize object to save remained value with index + let remain_with_index_obj = {} + + for ( let i =0; i list[int]: + for i in range(len(nums) - 1): + for k in range(i + 1, len(nums)): + if (nums[i] + nums[k] == target): + return ([i, k]) + diff --git a/two-sum/anniemon.js b/two-sum/anniemon.js new file mode 100644 index 000000000..403cefc67 --- /dev/null +++ b/two-sum/anniemon.js @@ -0,0 +1,20 @@ +/** + * 시간 복잡도: 최대 nums의 길이만큼 순회하므로, O(n) + * 공간 복잡도: map은 최대 nums의 길이 - 1 만큼의 공간을 차지하므로, O(n) + */ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + const map = new Map(); + + for(let i = 0; i < nums.length; i++) { + const complement = target - nums[i]; + if(map.has(complement)) { + return [i, map.get(complement)] + } + map.set(nums[i], i); + } +}; diff --git a/two-sum/bus710.go b/two-sum/bus710.go new file mode 100644 index 000000000..7542c9f1e --- /dev/null +++ b/two-sum/bus710.go @@ -0,0 +1,15 @@ +// O(n/2) as we only visit the half of the i*j + +package hello + +func twoSum(nums []int, target int) []int { + for i := range nums { + for j := i + 1; j < len(nums); j++ { + if (nums[i] + nums[j]) == target { + return []int{i, j} + } + } + } + + return nil +} diff --git a/two-sum/changchanghwang.go b/two-sum/changchanghwang.go new file mode 100644 index 000000000..7a4abf675 --- /dev/null +++ b/two-sum/changchanghwang.go @@ -0,0 +1,15 @@ +// Time: O(n) +// Space: O(n) +func twoSum(nums []int, target int) []int { + m := make(map[int]int) + + // O(n) + for i, num := range nums { + // O(1) + if j, ok := m[target-num]; ok && j != i { // target = num2 + num1 -> num2 = target - num1 을 이용하여 두 수를 찾는다. + return []int{j, i} + } + m[num] = i // 없다면 현재 수를 키로 하여 인덱스를 저장한다. + } + return nil +} diff --git a/two-sum/dalpang81.java b/two-sum/dalpang81.java new file mode 100644 index 000000000..1742ee8af --- /dev/null +++ b/two-sum/dalpang81.java @@ -0,0 +1,23 @@ +/* +* 시간복잡도 : O(n) +* 공간복잡도 : O(n) +* */ + +import java.util.HashMap; +import java.util.Map; + +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + + if (map.containsKey(complement)) { + return new int[] { map.get(complement), i }; + } + map.put(nums[i], i); + } + return null; + } +} diff --git a/two-sum/donghyeon95.java b/two-sum/donghyeon95.java new file mode 100644 index 000000000..8f72e6b5c --- /dev/null +++ b/two-sum/donghyeon95.java @@ -0,0 +1,31 @@ +import java.util.HashMap; +import java.util.HashSet; + +class Solution { + public int[] twoSum(int[] nums, int target) { + // // O(N^2) + // for (int i =0; i< nums.length-1; i++) { + // for (int j=i+1; j map = new HashMap<>(); + for (int i=0; i List[int]: + map = {} + for i in range(len(nums)): + pairNum = target - nums[i] + if pairNum in map: + return [map.get(pairNum), i] + map[nums[i]] = i diff --git a/two-sum/easyone-jwlee.go b/two-sum/easyone-jwlee.go new file mode 100644 index 000000000..42d736d64 --- /dev/null +++ b/two-sum/easyone-jwlee.go @@ -0,0 +1,20 @@ +// 풀이 +// map의 key에 값, value에 index를 넣어, target-num이 map에 존재할 때를 찾기. +// 오직 하나의 답만 무조건 존재한다고 했기 때문에 찾자마자 return. + +// TC +// 가장 마지막 인덱스까지 가서야 값을 구할 수 있었다고 하면, nums의 길이만큼 for문을 한바퀴 돌기때문에 O(n). + +// SC +// 중복없이 마지막 인덱스까지 가서 값을 구한다면 들어오는 nums의 길이만큼 map도 공간을 차지하게 되므로 O(n). + +func twoSum(nums []int, target int) []int { + m := make(map[int]int) + for i, num := range nums { + if index, ok := m[target-num]; ok { + return []int{index, i} + } + m[num] = i + } + return []int{0, 0} +} diff --git a/two-sum/ekgns33.java b/two-sum/ekgns33.java new file mode 100644 index 000000000..097903bb7 --- /dev/null +++ b/two-sum/ekgns33.java @@ -0,0 +1,39 @@ +import java.util.HashMap; +import java.util.Map; + +/* +input : array of integers, single integer target +output : indices of the two numbers that they add up to target +constraint: +1) is integer positive? +no [-10^9, 10^9] +2) is there any duplicates? +yes. but only one valid answer exists +3) can i reuse elem? +no + +sol1) brute force +nested for loop. tc: O(n^2), sc: O(1) when n is the length of input + +sol2) better solution with hash map +iterate through the array + check if target - current elem exists + if return pair of indices + else save current elem and continue + +tc : O(n), sc: O(n) when n is the length of input + + */ +class Solution { + public int[] twoSum(int[] nums, int target) { + Map prev = new HashMap<>(); + for(int i = 0; i < nums.length; i++) { + int key = target - nums[i]; + if(prev.containsKey(key)) { + return new int[] {prev.get(key), i}; + } + prev.put(nums[i], i); + } + return null; + } +} diff --git a/two-sum/eunhwa99.java b/two-sum/eunhwa99.java new file mode 100644 index 000000000..5edf3eede --- /dev/null +++ b/two-sum/eunhwa99.java @@ -0,0 +1,80 @@ +// 문제 요구사항 -> O(n^2) 보다 작은 시간복잡도로 구현 필요 +// 문제를 보자마자 생각난 것 -> 이분탐색 (2 원소 합이 target 인 것을 구해야 하므로) +// 이분 탐색 시간 복잡도 -> 정렬(O(nlogn)) + 이분탐색 (log(n)) -> nlogn +// 공간 복잡도 -> 배열 크기 만큼 공간 필요 (n) + +import java.util.Arrays; +import java.util.HashMap; + +class ValueIndex implements Comparable { + int value; + int index; + + // ValueIndex 객체를 정렬할 때 value 기준으로 오름차순 정렬 + @Override + public int compareTo(ValueIndex other) { + return Integer.compare(this.value, other.value); + } +} + +class Solution { + + public int[] twoSum(int[] nums, int target) { + int size = nums.length; + ValueIndex[] valueIndex = new ValueIndex[size]; + for (int i = 0; i < size; ++i) { + valueIndex[i] = new ValueIndex(); + valueIndex[i].value = nums[i]; + valueIndex[i].index = i; // 정렬 전 original index 저장 + } + Arrays.sort(valueIndex); // 정렬 + int left = 0; + int right = nums.length - 1; + + while (left < right) { + int leftVal = valueIndex[left].value; + int rightVal = valueIndex[right].value; + int sum = leftVal + rightVal; + + if (sum < target) { // target 보다 합이 작으면, left 값이 커져야 함 + left += 1; + } else if (sum > target) { + right -= 1; // target 보다 합이 크면, right 값이 작아져야 함 + } else { // sum = target 이면 끝! + break; + } + } + + return new int[]{valueIndex[left].index, valueIndex[right].index}; + } +} + + +/** + * hashMap을 이용한 O(n) 방법도 있다고 해서 추가 구현해보았습니다. (시간/공간 복잡도 O(n)) + */ + +class Solution { + + public int[] twoSum(int[] nums, int target) { + HashMap numMap = new HashMap<>(); + int left = 0, right = 0; + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; // 현재 숫자와 합쳐서 target을 만드는 숫자 + + // 이미 그 숫자가 해시맵에 있다면, 두 인덱스를 반환 + if (numMap.containsKey(complement)) { + left = numMap.get(complement); + right = i; + break; + } + + // 해시맵에 현재 숫자와 인덱스를 추가 + numMap.put(nums[i], i); + } + + return new int[]{left, right}; + + } +} + diff --git a/two-sum/forest000014.java b/two-sum/forest000014.java new file mode 100644 index 000000000..dc9f0436d --- /dev/null +++ b/two-sum/forest000014.java @@ -0,0 +1,64 @@ +/* +runtime 23 ms, beats 50.28% +memory 45.12 MB, beats 20.14% + +time complexity: O(nlogn) +- numsArray 정렬: O(nlogn) +- binary search: O(nlogn) + - i iteration: O(n) + - i번째 binary search: O(logn) + +space complexity: O(n) +- numsArray: O(n) +*/ + +class Solution { + public int[] twoSum(int[] nums, int target) { + ArrayList numsArray = IntStream.range(0, nums.length) + .mapToObj(i -> new Tuple(i, nums[i])) + .collect(Collectors.toCollection(ArrayList::new)); + + numsArray.sort(Comparator.comparing(tuple -> tuple.val)); + + int n = numsArray.size(); + + for (int i = 0; i < n; i++) { + int x = target - numsArray.get(i).val; + int j = -1; + int l = i + 1; + int r = n - 1; + boolean found = false; + while (l <= r) { + int m = (r - l) / 2 + l; + if (numsArray.get(m).val == x) { + j = m; + found = true; + break; + } else if (numsArray.get(m).val < x) { + l = m + 1; + } else { + r = m - 1; + } + } + + if (found) { + int[] ans = new int[2]; + ans[0] = numsArray.get(i).ref; + ans[1] = numsArray.get(j).ref; + return ans; + } + } + + return null; + } + + public class Tuple { + public final Integer ref; + public final Integer val; + + public Tuple(Integer ref, Integer val) { + this.ref = ref; + this.val = val; + } + } +} diff --git a/two-sum/gmlwls96.kt b/two-sum/gmlwls96.kt new file mode 100644 index 000000000..27b6dd147 --- /dev/null +++ b/two-sum/gmlwls96.kt @@ -0,0 +1,29 @@ +class Solution { + // 시간 : O(NlogN)-정렬하는데 드는 시간복잡도., 공간(2N) + fun twoSum(nums: IntArray, target: Int): IntArray { + val sortNums = List(nums.size) { listOf(nums[it], it) }.sortedBy { it[0] } + // 1. list( list('값', 'index')) 형태의 list를 만들고 값을 기준으로 정렬한다. + + var i = 0 + var j = sortNums.lastIndex + // 2. 2포인터 방식으로 두 값을 합했을때 target이 되는 값을 찾는다. + while (i < j) { + val sum = sortNums[i][0] + sortNums[j][0] + when { + sum == target -> { // target과 sum이 일치할시 바로 return. + return intArrayOf( + min(sortNums[i][1], sortNums[j][1]), + max(sortNums[i][1], sortNums[j][1]) + ) + } + sum < target -> { // sum이 target보다 값이 작은경우 i를 한칸씩 더한다. + i++ + } + sum > target -> { // sum이 target보다 값이 큰경우 j를 한칸씩 내린다. + j-- + } + } + } + return intArrayOf() + } +} diff --git a/two-sum/gwbaik9717.js b/two-sum/gwbaik9717.js new file mode 100644 index 000000000..c7b1397de --- /dev/null +++ b/two-sum/gwbaik9717.js @@ -0,0 +1,22 @@ +// Time complexity: O(n) +// Space complexity: O(n) + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function (nums, target) { + const map = new Map(); + + for (let i = 0; i < nums.length; i++) { + const num = nums[i]; + const diff = target - num; + + if (map.has(diff)) { + return [i, map.get(diff)]; + } else { + map.set(num, i); + } + } +}; diff --git a/two-sum/heypaprika.py b/two-sum/heypaprika.py new file mode 100644 index 000000000..f2c193b6a --- /dev/null +++ b/two-sum/heypaprika.py @@ -0,0 +1,19 @@ +""" +복잡도 : 예상 -> 예상한 이유 + +시간 복잡도 : O(n) -> 딕셔너리 키로 검색하는 것은 O(1), 따라서 for 문 1개로 O(n) +공간 복잡도 : O(n) -> n 수 만큼 반복되면서 값이 할당됨. +""" +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_dict = {} + n = len(nums) + + for i in range(n): + num_A = nums[i] + num_B = target - num_A + if num_B in num_dict: + return [i, num_dict[num_B]] + num_dict[num_A] = i + return [] + diff --git a/two-sum/higeuni.js b/two-sum/higeuni.js new file mode 100644 index 000000000..466f99ddd --- /dev/null +++ b/two-sum/higeuni.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + * + * Time Complexity: O(n) + * Space Complexity: O(n) + */ +var twoSum = function(nums, target) { + const map = new Map(); + + for (let i = 0; i < nums.length; ++i) { + const diff = target - nums[i]; + + if (map.has(diff)) { + return [map.get(diff), i]; + } + + map.set(nums[i], i); + } +}; + diff --git a/two-sum/imsosleepy.java b/two-sum/imsosleepy.java new file mode 100644 index 000000000..7ff6f1019 --- /dev/null +++ b/two-sum/imsosleepy.java @@ -0,0 +1,59 @@ +// hashmap 조회 방식은 O(N) +// 3ms +public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + if (map.containsKey(complement)) { + return new int[] { map.get(complement), i }; + } + map.put(nums[i], i); + } + return null; +} + +// 첫 생각 : 정렬 -> 투포인터 +public int[] twoSum1(int[] nums, int target) { + Arrays.sort(nums); + int left = 0; + int right = nums.length-1; + int sum = 0; + while(left < right) { + sum = nums[left] + nums[right]; + if(target > sum) { + left++; + } + if(target < sum) { + right--; + } + if(target == sum) { + break; + } + } + return new int[]{left, right}; +} + +// 투포인터는 O(N)에 충족하지만 정렬이 nlog(n)임 +// 9ms +public int[] twoSum2(int[] nums, int target) { + int[][] indexedNums = new int[nums.length][2]; + for (int i = 0; i < nums.length; i++) { + indexedNums[i][0] = nums[i]; + indexedNums[i][1] = i; + } + + Arrays.sort(indexedNums, Comparator.comparingInt(a -> a[0])); + + int left = 0, right = nums.length - 1; + while (left < right) { + int sum = indexedNums[left][0] + indexedNums[right][0]; + if (sum == target) { + return new int[] { indexedNums[left][1], indexedNums[right][1] }; + } else if (sum < target) { + left++; + } else { + right--; + } + } + return new int[]{left, right}; +} diff --git a/two-sum/jinah92.py b/two-sum/jinah92.py new file mode 100644 index 000000000..e8b204155 --- /dev/null +++ b/two-sum/jinah92.py @@ -0,0 +1,12 @@ +# O(n) time, O(n) space + +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_set = {} + + for idx, num in enumerate(nums): + other_num = target - num + if other_num in num_set: + return [idx, num_set[other_num]] + else: + num_set[num] = idx diff --git a/two-sum/limlimjo.js b/two-sum/limlimjo.js new file mode 100644 index 000000000..eade7cf51 --- /dev/null +++ b/two-sum/limlimjo.js @@ -0,0 +1,55 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function (nums, target) { + for (let i = 0; i < nums.length; i++) { + for (let j = 0; j < nums.length; j++) { + if (i !== j) { + if (nums[i] + nums[j] === target) { + return [i, j]; + } + } + } + } +}; + +// 처음에 풀었던 방법 -> 시간 복잡도가 O(n^2)로 nums 배열에 있는 값이 늘어날수록 성능상 좋지 못함 +// 시간 복잡도: O(n^2) +// 공간 복잡도: O(1) + +// 두 번째 푼 방법 -> 이전에 threeSum 문제 풀 때 정렬 + 포인터 이용한 것처럼 이 문제도 그런식으로 품 +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function (nums, target) { + const numsIndex = nums.map((num, i) => ({ num, i })); // 원래 인덱스 저장 + //console.log(numsIndex); + + numsIndex.sort((a, b) => a.num - b.num); // 오름차순 정렬 + //console.log(numsIndex); + + // left와 right 포인터 이용해 target값과 동일한 것 찾기 + let left = 0; + let right = numsIndex.length - 1; + + while (left < right) { + const sum = numsIndex[left].num + numsIndex[right].num; + + if (sum > target) { + right--; + } else if (sum < target) { + left++; + } else { + return [numsIndex[left].i, numsIndex[right].i]; + } + } + return null; +}; + +// 첫 번째 푼 방법보다 공간 복잡도가 늘어났지만 시간 복잡도는 줄어듦 +// 시간 복잡도: O(n log n) +// 공간 복잡도: O(n) diff --git a/two-sum/mike2ox.ts b/two-sum/mike2ox.ts new file mode 100644 index 000000000..c8c883692 --- /dev/null +++ b/two-sum/mike2ox.ts @@ -0,0 +1,23 @@ +/** + * Source: https://leetcode.com/problems/two-sum/ + * 풀이방법: Map을 이용하여 필요한 나머지 숫자를 저장하면서 확인 + * 시간복잡도: O(n) + * 공간복잡도: O(n) + */ +function twoSum(nums: number[], target: number): number[] { + // nums의 값을 key로, 인덱스를 value로 저장하는 Map + const numMap = new Map(); + + for (let i = 0; i < nums.length; i++) { + const remain = target - nums[i]; // 필요한 나머지 숫자 계산 + + // 필요한 나머지 숫자가 Map에 있는지 체크 + if (numMap.has(remain)) { + return [numMap.get(remain)!, i]; + } + // 현재 숫자와 인덱스 저장 + numMap.set(nums[i], i); + } + + return []; +} diff --git a/two-sum/minji-go.java b/two-sum/minji-go.java new file mode 100644 index 000000000..8464665fd --- /dev/null +++ b/two-sum/minji-go.java @@ -0,0 +1,21 @@ +/* + Problem: https://leetcode.com/problems/two-sum/ + Description: return indices of the two numbers such that they add up to target. not use the same element twice. + Topics: Array, Hash Table + Time Complexity: O(N), Runtime 2ms + Space Complexity: O(N), Memory 45.1MB +*/ +class Solution { + public int[] twoSum(int[] nums, int target) { + Map numIndex = new HashMap<>(); + for(int secondIndex=0; secondIndex numMap = new HashMap<>(); + + for(int i = 0; i < nums.length; i++) { + numMap.put(nums[i], i); + } + + for(int i = 0; i < nums.length; i++) { + int pairNum = target - nums[i]; + if(numMap.containsKey(pairNum) && numMap.get(pairNum) != i) { + return new int[]{i, numMap.get(target - nums[i])}; + } + } + + return new int[2]; + } +} diff --git a/two-sum/mmyeon.ts b/two-sum/mmyeon.ts new file mode 100644 index 000000000..3b3d8603f --- /dev/null +++ b/two-sum/mmyeon.ts @@ -0,0 +1,31 @@ +/** + * + * 접근 방법 : + * - 이미 방문한 숫자와 인덱스를 맵에 저장 + * - nums 배열 순회하면서, 찾는 숫자 가 없으면 맵에 값, 인덱스 추가하기 + * - 맵에 존재하면 현재 인덱스와, 해당 숫자의 인덱스 담아서 즉시 리턴하기 + * + * 시간복잡도 : O(n) + * - nums 배열 길이만큼 1회 순회하니까 O(n) + * - 맵 조회 및 삽입은 O(1) + * + * 공간복잡도 : O(n) + * - 맵에 배열의 값 저장하니까 O(n) + * + * 엣지 케이스 : + * - 동일한 숫자가 있는 경우 : [3, 3], 6 => [0,1] + */ + +function twoSum(nums: number[], target: number): number[] { + const map = new Map(); + + for (let i = 0; i < nums.length; i++) { + const neededValue = target - nums[i]; + + if (map.has(neededValue)) { + return [map.get(neededValue)!, i]; + } + + map.set(nums[i], i); + } +} diff --git a/two-sum/nakjun12.ts b/two-sum/nakjun12.ts new file mode 100644 index 000000000..8c1ac2570 --- /dev/null +++ b/two-sum/nakjun12.ts @@ -0,0 +1,20 @@ +/* + * TC: O(n) + * SC: O(n) + * */ +function twoSum(nums: number[], target: number): number[] { + const indices = {}; + + for (let i = 0; i < nums.length; i++) { + const curNum = nums[i]; + const complement = target - curNum; + + if (complement in indices) { + return [indices[complement], i]; + } + + indices[curNum] = i; + } + + return []; +} diff --git a/two-sum/neverlish.go b/two-sum/neverlish.go new file mode 100644 index 000000000..b8bc6f067 --- /dev/null +++ b/two-sum/neverlish.go @@ -0,0 +1,49 @@ +// 시간복잡도: O(n) +// 공간복잡도: O(n) + +package main + +import "testing" + +func TestTwoSum(t *testing.T) { + result1 := twoSum([]int{2, 7, 11, 15}, 9) + + if len(result1) != 2 { + t.Errorf("Expected 2, got %d", len(result1)) + } + + if result1[0] != 0 && result1[1] != 1 { + t.Errorf("Expected [0, 1], got %v", result1) + } + + result2 := twoSum([]int{3, 2, 4}, 6) + + if len(result2) != 2 { + t.Errorf("Expected 2, got %d", len(result2)) + } + + if result2[0] != 1 && result2[1] != 2 { + t.Errorf("Expected [1, 2], got %v", result2) + } + + result3 := twoSum([]int{3, 3}, 6) + if len(result3) != 2 { + t.Errorf("Expected 2, got %d", len(result3)) + } + + if result3[0] != 0 && result3[1] != 1 { + t.Errorf("Expected [0, 1], got %v", result3) + } +} + +func twoSum(nums []int, target int) []int { + seen := map[int]int{} + for i, num := range nums { + complement := target - num + if _, ok := seen[complement]; ok { + return []int{seen[complement], i} + } + seen[num] = i + } + return nil +} diff --git a/two-sum/paragon0107.java b/two-sum/paragon0107.java new file mode 100644 index 000000000..01da0e33c --- /dev/null +++ b/two-sum/paragon0107.java @@ -0,0 +1,21 @@ + +import java.util.HashMap; +import java.util.Map; + +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for(int i =0;i List[int]: + subtract_map = {} + + for i, num in enumerate(nums): + if num in subtract_map: + return [i, subtract_map[num]] + else: + subtract_map[target - num] = i + + +# 시간 복잡도: O(n) +# - nums 배열을 한 번 순회하며 각 요소를 확인하므로 시간 복잡도는 O(n)입니다. +# +# 공간 복잡도: O(n) +# - 추가로 사용하는 subtract_map 딕셔너리에는 최악의 경우 nums 배열의 모든 요소가 저장되므로 +# 공간 복잡도는 O(n)입니다. diff --git a/two-sum/river20s.java b/two-sum/river20s.java new file mode 100644 index 000000000..621660e25 --- /dev/null +++ b/two-sum/river20s.java @@ -0,0 +1,24 @@ +/* + * T.C: O(n) -> 배열 nums를 한 번 순회 + * S.C: O(n) → 최대 n개의 요소가 저장됨 + */ +import java.util.HashMap; + +class Solution { + public int[] twoSum(int[] nums, int target) { + + HashMap map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int k = target - nums[i]; + + if (map.containsKey(k)) { + return new int[] { map.get(k), i }; + } + + map.put(nums[i], i); + } + throw new IllegalArgumentException("exception handling for java compilation"); + + } +} + diff --git a/two-sum/sungjinwi.py b/two-sum/sungjinwi.py new file mode 100644 index 000000000..dbf40b964 --- /dev/null +++ b/two-sum/sungjinwi.py @@ -0,0 +1,13 @@ +""" + TC : for문 내부 for문 + O(N^2) + SC : 추가적인 메모리 쓰지 않으므로 + O(1) +""" + +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + for i in nums : + for j in nums : + if i != j and nums[i] + nums[j] == target : + return [i, j] diff --git a/two-sum/taewanseoul.ts b/two-sum/taewanseoul.ts new file mode 100644 index 000000000..97674206c --- /dev/null +++ b/two-sum/taewanseoul.ts @@ -0,0 +1,21 @@ +/** + * 1. Two Sum + * Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. + * You may assume that each input would have exactly one solution, and you may not use the same element twice. + * You can return the answer in any order. + * + * https://leetcode.com/problems/two-sum/description/ + */ + +// O(n) time +// O(n) space +function twoSum(nums: number[], target: number): number[] { + const map = new Map(); + + for (let i = 0; i < nums.length; i++) { + if (map.has(target - nums[i])) { + return [i, map.get(target - nums[i])!]; + } + map.set(nums[i], i); + } +} diff --git a/two-sum/thispath98.py b/two-sum/thispath98.py new file mode 100644 index 000000000..cca31e787 --- /dev/null +++ b/two-sum/thispath98.py @@ -0,0 +1,23 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + """ + Intuition: + 기존에 풀었던 3sum 문제와 유사하게, + 해시에 현재 숫자와 더해서 target이 되는 값을 찾는다. + 만약 없을 경우, 해시에 현재 값과 인덱스를 저장한다. + + Time Complexity: + O(N): + 해시는 접근하는 데에 O(1)이 소요되고, + 총 N번 반복해야 하므로 시간복잡도는 O(N)이다. + + Space Complexity: + O(N): + 최악의 경우 해시에 N개의 숫자와 인덱스를 저장해야 한다. + """ + complement_dict = {} + for i, num in enumerate(nums): + if target - num in complement_dict: + return [complement_dict[target - num], i] + else: + complement_dict[num] = i