diff --git a/longest-common-subsequence/Yjason-K.ts b/longest-common-subsequence/Yjason-K.ts new file mode 100644 index 000000000..45cf5035e --- /dev/null +++ b/longest-common-subsequence/Yjason-K.ts @@ -0,0 +1,37 @@ +/** + * 두 문자열의 최장 공통 부분 문자열의 길이 구하기. + * + * @param {string} text1 - 첫 번째 문자열 + * @param {string} text2 - 두 번째 문자열 + * @returns {number} - 최장 공통 부분 문자열의 길이 + * + * 시간 복잡도: + * - O(m * n) : 두 문자열의 길이를 각각 m, n이라고 할 때, DP 테이블의 모든 요소를 계산합니다. + * + * 공간 복잡도: + * - O(m * n) : m+1 x n+1 크기의 2차원 DP 테이블을 생성하여 사용합니다. + */ +function longestCommonSubsequence(text1: string, text2: string): number { + const m = text1.length; + const n = text2.length; + + // DP 테이블 생성 (m+1 x n+1 크기) + const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + + // DP 계산 + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + if (text1[i - 1] === text2[j - 1]) { + // 문자가 일치하면 이전 값에 +1 + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + // 문자가 다르면 왼쪽과 위쪽 값 중 큰 값 선택 + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + // 최장 공통 부분 문자열의 길이 + return dp[m][n]; +} + diff --git a/longest-repeating-character-replacement/Yjason-K.ts b/longest-repeating-character-replacement/Yjason-K.ts new file mode 100644 index 000000000..0d88eb6db --- /dev/null +++ b/longest-repeating-character-replacement/Yjason-K.ts @@ -0,0 +1,50 @@ +/** + * sliding window + * 문자열 k번 변경 가능한, 가장 긴 반복 문자열의 길이 구하기. + * @param {string} s - 문자열 + * @param {number} k - 문자 변경 가능 횟수 + * @return {number} - 가장 긴 부분 문자열의 길이 + * + * 시간 복접도: O(n) + * - 문자길이 만큼의 1회 순회 + * + * 공간 복잡도: O(1) + * - 알파벳 26개의 제한된 Map 사용 + * + */ +function characterReplacement(s: string, k: number): number { + // 문자의 빈도를 저장할 Map + const charFreq = new Map(); + + // window 왼쪽 포인터 + let left = 0; + + // 최대 길이, 최대 빈도 초기화 + let maxLength = 0; + let maxFreq = 0; + + // 오른쪽 포인터를 0부터 이동하며 window 크기 조절 + for (let right = 0; right < s.length; right++) { + const char = s[right]; + + // 현재 문자의 빈도 증가 + charFreq.set(char, (charFreq.get(char) || 0) + 1); + + // 윈도우 내에서 가장 많이 등장한 문자의 빈도 갱신 + maxFreq = Math.max(maxFreq, charFreq.get(char)!); + + // 조건: (윈도우 크기 - maxFreq > k)일 때, 왼쪽 포인터 이동 + if (right - left + 1 - maxFreq > k) { + const leftChar = s[left]; + charFreq.set(leftChar, charFreq.get(leftChar)! - 1); // 왼쪽 문자 제거 + left++; // 윈도우 축소 + } + + // 현재 윈도우 크기를 기준으로 최대 길이 갱신 + maxLength = Math.max(maxLength, right - left + 1); + } + + return maxLength; + +} + diff --git a/number-of-1-bits/Yjason-K.ts b/number-of-1-bits/Yjason-K.ts new file mode 100644 index 000000000..e43328fee --- /dev/null +++ b/number-of-1-bits/Yjason-K.ts @@ -0,0 +1,20 @@ +/** + * 주어진 숫자 `n`의 2진수 표현에서 1의 개수를 계산. + * + * @param {number} n - 1의 개수를 계산할 숫자 (양의 정수) + * @returns {number} - 2진수에서 1의 개수 + * + * 시간 복잡도: O(k) + * - `k`는 숫자 `n`의 2진수 표현 길이 (log2(n)) + * - `toString(2)` 연산과 배열 순회를 포함. + * + * 공간 복잡도: O(k) + * - 2진수 문자열과 문자열 배열을 저장하는 데 사용되는 메모리 포함. + */ +function hammingWeight(n: number): number { + // 1. 입력 숫자 `n`을 2진수 문자열로 변환 + // 2. 2진수 문자열을 개별 문자로 나누어 배열로 변환 + // 3. 배열에서 1의 개수를 누적하여 합산 + return n.toString(2).split('').reduce((a, b) => a + Number(b), 0); +}; + diff --git a/sum-of-two-integers/Yjason-K.ts b/sum-of-two-integers/Yjason-K.ts new file mode 100644 index 000000000..ee71a9777 --- /dev/null +++ b/sum-of-two-integers/Yjason-K.ts @@ -0,0 +1,18 @@ +/** + * +, - 기호를 사용하지 않고 두 정수의 합을 구하기 + * @param {number} a - 정수 + * @param {number} b - 정수 + * @return {number} - 두 정수의 합 + */ +function getSum(a: number, b: number): number { + // 1. XOR 연산으로 덧셈 처리 + // 2. AND 연산으로 올림 처리 + // 3. 올림이 없을 때까지 반복 + while (b !== 0) { + const carry = a & b; + a = a ^ b; + b = carry << 1; + } + return a; +} +