diff --git a/contains-duplicate/Yjason-K.ts b/contains-duplicate/Yjason-K.ts new file mode 100644 index 000000000..ada16664e --- /dev/null +++ b/contains-duplicate/Yjason-K.ts @@ -0,0 +1,18 @@ +/** + * Set 자료구조를 사용하여 중복 확인 (시간 복잡도: O(n) ) + * @param nums 중복 검사할 숫자 배열 + * @returns boolean 중복 여부 + */ + +function containsDuplicate(nums: number[]): boolean { + let unique: Set = new Set([]); + for (const num of nums) { + if (unique.has(num)) { + return true + } else { + unique.add(num) + } + } + return false; +}; + diff --git a/house-robber/Yjason-K.ts b/house-robber/Yjason-K.ts new file mode 100644 index 000000000..a62d74e95 --- /dev/null +++ b/house-robber/Yjason-K.ts @@ -0,0 +1,31 @@ +/** + * 주어진 배열에서 인접한 집을 털지 않고 훔칠 수 있는 최대 금액을 계산하는 함수 + * - 시간 복잡도: O(n) + * - 배열을 한 번 순회하면서 최대 금액을 계산 + * - 공간 복잡도: O(1) + * - 추가 배열 없이 변수만 사용하여 공간 효율성을 최적화 + * + * @param {number[]} nums - 각 집에 있는 돈의 양을 나타내는 배열 + * @returns {number} - 경보를 울리지 않고 훔칠 수 있는 최대 금액 + */ +function rob(nums: number[]): number { + if (nums.length === 0) return 0; // 빈 배열 처리 + if (nums.length === 1) return nums[0]; // 집이 한 채만 있는 경우, 그 집의 돈 반환 + + // 1. 변수 초기화: 이전 두 집까지의 최대 금액 + let prev2 = 0; // 두 번째 이전 집까지의 최대 금액 + let prev1 = nums[0]; // 첫 번째 이전 집까지의 최대 금액 + + // 2. 배열 순회: 각 집에서 훔칠 수 있는 최대 금액 계산 + for (let i = 1; i < nums.length; i++) { + // 현재 집까지의 최대 금액은 (현재 집 + prev2) 또는 prev1 중 더 큰 값 + const cur = Math.max(nums[i] + prev2, prev1); + + // 이전 두 집의 최대 금액 업데이트 + prev2 = prev1; + prev1 = cur; + } + + return prev1; // 마지막 집까지의 최대 금액 반환 +} + diff --git a/longest-consecutive-sequence/Yjason-K.ts b/longest-consecutive-sequence/Yjason-K.ts new file mode 100644 index 000000000..ae0f29a31 --- /dev/null +++ b/longest-consecutive-sequence/Yjason-K.ts @@ -0,0 +1,41 @@ +/** + * 주어진 배열에서 가장 긴 연속된 숫자 시퀀스의 길이를 반환하는 함수 + * - 시간 복잡도: O(n) + * - O(n): Set에 숫자를 추가하고, 각 숫자를 순회하면서 연속된 시퀀스를 계산 + * - 공간 복잡도: O(n) + * - O(n): 숫자를 저장하기 위한 Set 사용 + * + * @param {number[]} nums - 정수 배열 + * @returns {number} - 가장 긴 연속된 숫자 시퀀스의 길이 + */ +function longestConsecutive(nums: number[]): number { + if (nums.length === 0) return 0; // 빈 배열 처리 (길이 0 반환) + + // 1. 배열을 Set에 저장하여 중복을 제거하고 빠른 조회를 가능하게 함 O(n) + const numSet = new Set(nums); + + let longestSeq = 0; // 가장 긴 연속 시퀀스 길이를 저장할 변수 + + // 2. 각 숫자가 시퀀스의 시작점인지 확인 + for (const num of numSet) { + // 숫자 `num`이 시퀀스의 시작점인지 확인 + // (num-1이 Set에 없다면 num은 시퀀스의 시작점) + if (!numSet.has(num - 1)) { + // 새로운 시퀀스 시작 + let curNum = num; + let curSeq = 1; + + // 3. 시퀀스가 끝날 때까지 길이를 계산 O(n) + while (numSet.has(curNum + 1)) { + curNum += 1; // 현재 숫자를 1 증가 + curSeq += 1; // 시퀀스 길이를 1 증가 + } + + // 4. 가장 긴 시퀀스 길이를 업데이트 + longestSeq = Math.max(longestSeq, curSeq); + } + } + + return longestSeq; // 가장 긴 연속 시퀀스의 길이 반환 +} + diff --git a/top-k-frequent-elements/Yjason-K.ts b/top-k-frequent-elements/Yjason-K.ts new file mode 100644 index 000000000..9f986bdc9 --- /dev/null +++ b/top-k-frequent-elements/Yjason-K.ts @@ -0,0 +1,36 @@ +/** + * 배열에서 각 숫자의 빈도를 계산한 후 상위 k개의 빈도 요소를 반환하는 함수 + * - 시간 복잡도: O(n + m log m) + * - O(n): 숫자 빈도를 계산하는 루프 + * - O(m log m): 고유 숫자(m)에 대한 정렬 + * - 공간 복잡도: O(m) + * - 고유 숫자(m)에 비례한 Map과 정렬된 배열 사용 + * + * @param {number[]} nums - 숫자 배열 + * @param {number} k - 반환할 상위 빈도 요소의 개수 + * @returns {number[]} 상위 k개의 빈도 요소 (순서는 상관 없음) + */ +function topKFrequent(nums: number[], k: number): number[] { + let numMap = new Map(); // 숫자의 빈도를 저장할 Map + + // 1. 숫자 빈도 Map 생성 O(n) + for (const num of nums) { + // Map에 현재 숫자가 없으면 1로 초기화, 있으면 1 증가 + const value = numMap.get(num) ? numMap.get(num) + 1 : 1; + numMap.set(num, value); + } + + // 2. Map을 [숫자, 빈도수] 배열로 변환한 뒤 빈도수 기준 내림차순 정렬 O(m log m) + const sortedFrequent = [...numMap.entries()] // Map을 배열로 변환 + .sort((a, b) => b[1] - a[1]) // 빈도수 기준 내림차순 정렬 + + // 3. 상위 k개의 숫자만 추출 O(k) + .slice(0, k) + + // 4. 숫자(key)만 추출 O(k) + .map(entry => entry[0]); + + return sortedFrequent; +} + + diff --git a/valid-palindrome/Yjason-K.ts b/valid-palindrome/Yjason-K.ts new file mode 100644 index 000000000..7ed4839fe --- /dev/null +++ b/valid-palindrome/Yjason-K.ts @@ -0,0 +1,33 @@ +/** + * 문자열을 알파벳 대문자를 소문자로 변환 및 숫자만 남기는 변환 유틸 + * - 시간 복잡도: O(n) (입력된 문자열의 길이에 비례) + * + * @param {string} s - 정제할 물자열 + * @returns {string} - 소문자 알파벳과 숫자로 이루어진 문자열 + */ +const refinePhrase = (s:string) : string => s.toLowerCase().replace(/[^a-z0-9]/g, ''); + + +/** + * 문자열을 정제후 palindrome 여부 확인 하는 함수 + * - 시간 복잡도: O(n) (문자열 정제 + 투 포인터 알고리즘) + * + * @param {string} s palindrome 여부를 확인할 문자열 + * @returns {boolean} palindrome 여부 + */ +function isPalindrome(s: string): boolean { + const refined = refinePhrase(s); + + // two pointer를 활용한 palindrome 확인 O(n) + let left = 0, right = refined.length - 1; + while (left < right) { + if (refined[left] !== refined[right]) { + return false; + } + left++; + right--; + } + + return true; +} +