diff --git a/contains-duplicate/soobing2.ts b/contains-duplicate/soobing2.ts new file mode 100644 index 000000000..8d5a16e4f --- /dev/null +++ b/contains-duplicate/soobing2.ts @@ -0,0 +1,20 @@ +/** + * 문제 유형 + * - Array + * + * 문제 설명 + * - 중복된 수가 있는 경우 true, 없으면 false 반환 + * + * 아이디어 + * - 전체적으로 순회하면서 중복된 수가 있는지 확인 + * + */ +function containsDuplicate(nums: number[]): boolean { + const set = new Set(); + for (let i = 0; i < nums.length; i++) { + if (set.has(nums[i])) return true; + + set.add(nums[i]); + } + return false; +} diff --git a/house-robber/soobing2.ts b/house-robber/soobing2.ts new file mode 100644 index 000000000..ddfd0d5ed --- /dev/null +++ b/house-robber/soobing2.ts @@ -0,0 +1,42 @@ +/** + * 문제 유형: DP + * + * 문제 설명 + * - 바로 옆집을 한번에 털 수 없을때, 최대로 털 수 있는 돈을 구하는 문제 + * - 함정은, 홀수의 합 vs 짝수의 합만 비교해서는 안된다. 2개 초과해서 털 수 있는 경우가 있음 (ex. [2, 1, 1, 2]) + * + * 아이디어 + * - DP 문제 답게 Top-down, Bottom-up 두 개 다 풀 수 있음 + */ + +function robBottomUp(nums: number[]): number { + const n = nums.length; + const dp = Array(n).fill(0); + + if (n === 1) return nums[0]; + if (n === 2) return Math.max(nums[0], nums[1]); + + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + + for (let i = 2; i < n; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); + } + + return dp[n - 1]; +} + +function robTopDown(nums: number[]): number { + const n = nums.length; + const memo = new Map(); + + const dp = (i: number) => { + if (i < 0) return 0; + if (memo.has(i)) return memo.get(i); + + const res = Math.max(dp(i - 1)!, dp(i - 2)! + nums[i]); + memo.set(i, res); + return res; + }; + return dp(n - 1)!; +} diff --git a/longest-consecutive-sequence/soobing2.ts b/longest-consecutive-sequence/soobing2.ts new file mode 100644 index 000000000..2bc8306dd --- /dev/null +++ b/longest-consecutive-sequence/soobing2.ts @@ -0,0 +1,71 @@ +/** + * 문제 유형: 그래프(Union Find) + * + * 문제 설명 + * - 주어진 배열에서 가장 긴 연속된 수열의 길이를 구하는 문제 + * + * 아이디어 + * 1) 중복된 수 제거 후 순회하며 값이 1차이 나는 항목끼리 합집합 만들기 + * + * 미션 + * - 더 빠른 풀이: HashSet 기반 Greedy로 풀어보기. + * + */ +class UnionFind { + parent: Map = new Map(); + size: Map = new Map(); + + constructor(nums: number[]) { + for (const num of nums) { + this.parent.set(num, num); + this.size.set(num, 1); + } + } + + find(x: number): number { + if (this.parent.get(x) !== x) { + this.parent.set(x, this.find(this.parent.get(x)!)); + } + + return this.parent.get(x)!; + } + + union(x: number, y: number): void { + const rootX = this.find(x); + const rootY = this.find(y); + + if (rootX === rootY) return; + + const sizeX = this.size.get(rootX); + const sizeY = this.size.get(rootY); + if (sizeX < sizeY) { + this.parent.set(rootX, rootY); + this.size.set(rootY, sizeX + sizeY); + } else { + this.parent.set(rootY, rootX); + this.size.set(rootX, sizeX + sizeY); + } + } + + getMaxSize(): number { + let max = 0; + for (const size of this.size.values()) { + max = Math.max(max, size); + } + return max; + } +} +function longestConsecutive(nums: number[]): number { + if (nums.length === 0) return 0; + + const uniqueNums = Array.from(new Set(nums)); + const uf = new UnionFind(uniqueNums); + + for (const num of uniqueNums) { + if (uf.parent.has(num + 1)) { + uf.union(num, num + 1); + } + } + + return uf.getMaxSize(); +} diff --git a/top-k-frequent-elements/soobing2.ts b/top-k-frequent-elements/soobing2.ts new file mode 100644 index 000000000..7f92e62cc --- /dev/null +++ b/top-k-frequent-elements/soobing2.ts @@ -0,0 +1,93 @@ +/** + * 문제 유형: Heap + * + * 문제 설명 + * - 가장 빈도수가 많은 K개 Element 추출 + * + * 아이디어 + * 1) 빈도수 계산하여 index와 함께 Map에 저장, 빈도수를 기준으로 MinHeap 구성 + * 2) 빈도수 Map을 순회하면서 MinHeap에 추가 + MinHeap의 크기가 K를 초과하면 최소값 제거 (미리미리 빈도수가 많은 K개 Element를 만들어나가는 형식) + * 3) MinHeap에 남아있는 Element들의 index를 반환 + * + * 시간 복잡도: O(NlogK) + * 공간 복잡도: O(N) + */ +class MinHeap { + heap: [number, number][] = []; + + insert(item: [number, number]) { + this.heap.push(item); + this.bubbleUp(); + } + + private bubbleUp() { + let index = this.heap.length - 1; + while (index > 0) { + const parentIndex = Math.floor((index - 1) / 2); + if (this.heap[index][0] >= this.heap[parentIndex][0]) break; + [this.heap[index], this.heap[parentIndex]] = [ + this.heap[parentIndex], + this.heap[index], + ]; + index = parentIndex; + } + } + + extractMin(): [number, number] | undefined { + if (this.heap.length === 0) return undefined; + const min = this.heap[0]; + const end = this.heap.pop(); + if (this.heap.length > 0 && end !== undefined) { + this.heap[0] = end; + this.sinkDown(0); + } + return min; + } + + private sinkDown(index: number) { + const length = this.heap.length; + while (true) { + let left = 2 * index + 1; + let right = 2 * index + 2; + let smallest = index; + + if (left < length && this.heap[left][0] < this.heap[smallest][0]) { + smallest = left; + } + if (right < length && this.heap[right][0] < this.heap[smallest][0]) { + smallest = right; + } + if (index === smallest) break; + + [this.heap[index], this.heap[smallest]] = [ + this.heap[smallest], + this.heap[index], + ]; + index = smallest; + } + } + + peek(): [number, number] | undefined { + return this.heap[0]; + } + + size(): number { + return this.heap.length; + } +} +function topKFrequent(nums: number[], k: number): number[] { + const freqMap = new Map(); + for (const num of nums) { + freqMap.set(num, (freqMap.get(num) ?? 0) + 1); + } + + const minHeap = new MinHeap(); + for (const [num, count] of freqMap.entries()) { + minHeap.insert([count, num]); + if (minHeap.size() > k) { + minHeap.extractMin(); + } + } + + return minHeap.heap.map(([_, num]) => num); +} diff --git a/two-sum/soobing2.ts b/two-sum/soobing2.ts new file mode 100644 index 000000000..83720fa19 --- /dev/null +++ b/two-sum/soobing2.ts @@ -0,0 +1,25 @@ +/** + * 문제 유형 + * - Array + * + * 문제 설명 + * - 주어진 배열에서 두 수를 더해서 target 값이 되는 인덱스를 반환 + * + * 아이디어 + * - 순회하면서 map을 먼저 만들어두고, 다시 순회하면서 target-nums[i] 값이 있는지 확인 + */ +function twoSum(nums: number[], target: number): number[] { + const map = new Map(); + for (let i = 0; i < nums.length; i++) { + map.set(nums[i], i); + } + + for (let i = 0; i < nums.length; i++) { + const index = map.get(target - nums[i]); + if (i === index || index === undefined) continue; + + return [i, index]; + } + + return []; +}