diff --git a/contains-duplicate/novacat25.ts b/contains-duplicate/novacat25.ts new file mode 100644 index 0000000000..d28a56571b --- /dev/null +++ b/contains-duplicate/novacat25.ts @@ -0,0 +1,30 @@ +/* + 시간 복잡도(Time Complexity): 평균 O(n) + 공간 복잡도(Space Complexity): O(n) + 풀이 알고리즘: JavaScript Set 활용 + + 풀이 History + 1트: Array.find()를 이용해 중복 여부를 탐색했으나, + 반복적인 배열 탐색으로 인해 시간 초과(TLE) 발생. + + 2트: 배열 정렬 후 Binary Search를 활용하는 방법을 고려했으나, + 정렬에 필요한 추가적인 시간 비용으로 비효율적이라고 판단. + + 3트: Set 자료구조를 이용한 풀이로 변경. + Set.has()를 통해 기존 데이터의 존재 여부를 평균 O(1)에 확인하고, + Set.add()를 통해 방문한 숫자를 기록. +*/ + +const containsDuplicate = (nums: number[]): boolean => { + const numSet = new Set() + + for (const num of nums) { + if (numSet.has(num)) { + return true + } + + numSet.add(num) + } + + return false +} diff --git a/house-robber/novacat25.ts b/house-robber/novacat25.ts new file mode 100644 index 0000000000..6d388040bc --- /dev/null +++ b/house-robber/novacat25.ts @@ -0,0 +1,29 @@ +/* +시간 복잡도: O(n) +공간 복잡도: O(1) +풀이 알고리즘: DP(Dynamic Programming) 이용 (Space-Optimised DP) + +해설: dp[i] = max(dp[i-2] + nums[i], dp[i-1]) 로 점화식을 세울 수 있다. +dp[i-2]와 dp[i-1]만 있으면 dp[i]를 구할 수 있으므로, dp 배열을 만들지 않고 두 개의 변수(secondLast, last)만으로도 구현 가능하다. + +점화식: dp[i] = max(dp[i−2] + nums[i], dp[i−1]) +Dynamic Programming 기법에 의해, secondLast와 last를 다음 Iteration에서 재사용할 수 있도록 저장하여 공간 최적화(Space-Optimisation)를 활용할 수 있다. +*/ +const rob = (nums: number[]): number => { + const n = nums.length + + if (n === 1) return nums[0] + + let secondLast = 0 + let last = nums[0] + + let result = -1 + + for (let i = 1; i < n; i++) { + result = Math.max(nums[i] + secondLast, last) + secondLast = last + last = result + } + + return result +} diff --git a/longest-consecutive-sequence/novacat25.ts b/longest-consecutive-sequence/novacat25.ts new file mode 100644 index 0000000000..6b110536a5 --- /dev/null +++ b/longest-consecutive-sequence/novacat25.ts @@ -0,0 +1,31 @@ +/* +시간 복잡도(Time Complexity): 평균 O(n) +공간 복잡도(Space Complexity): 평균 O(n) +풀이 알고리즘: JavaScript Set 이용 + +풀이 History +1트: JavaScript Set을 떠올렸으나, for(const val of st) 부분에서 불필요한 부분을 탐색하여 TLE가 터졌다. (X) +2트: [...st]를 이용해 Set을 Array로 변환 후, for(const val of setArr)로 탐색하여 시간 복잡도를 개선했다. (O(n) 시간 복잡도) + +기타: Duplicate identifier 'longestConsecutive' 에러가 발생하는 듯하여 novacatLongestConsecutive라는 이름으로 함수를 변경함. +*/ + +const novacatLongestConsecutive = (nums: number[]): number => { + const numberSet = new Set(nums) + let result = 0 + + for (const val of numberSet) { + if (!numberSet.has(val - 1)) { + let cur = val + let cnt = 0 + while (numberSet.has(cur)) { + cur++ + cnt++ + } + + result = Math.max(result, cnt) + } + } + + return result +} diff --git a/top-k-frequent-elements/novacat25.ts b/top-k-frequent-elements/novacat25.ts new file mode 100644 index 0000000000..19427db186 --- /dev/null +++ b/top-k-frequent-elements/novacat25.ts @@ -0,0 +1,43 @@ +/* +공간 복잡도: O(n) +시간 복잡도: O(n) +풀이: nums의 length만큼 버킷을 생성하여 Bucket Sort 적용 후 빈도가 높은 순서대로 k개의 숫자를 선택한다. +풀이 History +1차: JavaScript Map + Max Heap을 이용해 k개의 숫자를 선택하는 방식으로 구현했다.(O(nlogk) 시간 복잡도) 문제 조건 상 시간 복잡도가 O(nlogn) 이하로 나와야 하므로 2차에서 Bucket Sort를 적용하여 O(n) 시간 복잡도로 구현하였다. +2차: 아래의 코드대로 Bucket Sort를 적용하여 k개의 숫자를 선택하는 방식으로 수정했다.(O(n) 시간 복잡도) +개선점: for 문을 그대로 쓰지 않고, 함수를 만들어서 재사용성을 높이는 방안도 좋을 것으로 생각됨. +*/ +const getBucketSort = (freqArr: Map, n: number): number[][] => { + // freq 값을 그대로 index로 활용하고 싶기 때문에 n+1개의 버킷을 생성한다.(index 0은 사용하지 않음) + const buckets: number[][] = Array.from({ length: n + 1 }, () => []) + + for (const [num, freq] of freqArr) { + buckets[freq].push(num) + } + + return buckets +} + +const topKFrequent = (nums: number[], k: number): number[] => { + const answerArr: number[] = [] + const freqMap = new Map() + + for (const val of nums) { + const count = (freqMap.get(val) || 0) + 1 + freqMap.set(val, count) + } + + const bucketArr = getBucketSort(freqMap, nums.length) + + for (let i = bucketArr.length - 1; i >= 0; i--) { + for (const num of bucketArr[i]) { + answerArr.push(num) + + if (answerArr.length === k) { + return answerArr + } + } + } + + return answerArr +} diff --git a/two-sum/novacat25.ts b/two-sum/novacat25.ts new file mode 100644 index 0000000000..2500b6895e --- /dev/null +++ b/two-sum/novacat25.ts @@ -0,0 +1,34 @@ +/* + 시간 복잡도(Time Complexity): 평균 O(n) + 공간 복잡도(Space Complexity): O(n) + 풀이 알고리즘: JavaScript Map 활용 + + 풀이 History + 1트: 완전 탐색을 이용해 정답은 맞췄으나, + 시간 복잡도가 O(n²)로 비효율적이었음. + + 2트: JavaScript Map을 활용하여 + 숫자와 인덱스를 Key-Value 형태로 관리. + 보완해야 할 숫자의 존재 여부를 평균 O(1)에 탐색하여 + 전체 시간 복잡도를 O(n)으로 개선. +*/ + +const twoSum = (nums: number[], target: number): number[] => { + const numToIndexMap: Map = new Map() + + for (let i = 0; i < nums.length; i++) { + const currentNum = nums[i] + const complement = target - currentNum + + const complementIndex = numToIndexMap.get(complement) + + if (complementIndex !== undefined) { + return [complementIndex, i] + } + + numToIndexMap.set(currentNum, i) + } + + // Fallback 값으로 임의로 반환하지 않고, 예외를 발생시켜 문제 조건에 맞지 않는 경우를 명시적으로 처리함. + throw new Error("No valid pair found") +}