diff --git a/combination-sum/clara-shin.js b/combination-sum/clara-shin.js new file mode 100644 index 000000000..b117549cd --- /dev/null +++ b/combination-sum/clara-shin.js @@ -0,0 +1,40 @@ +/** + * 주어진 배열에서 합이 target이 되는 모든 조합 찾기 + * 문제 특징: 같은 숫자를 여러 번 사용 가능 + * + * 백트래킹 알고리즘: 모든 가능성을 시도해보다가, 해결책이 아닌 경우 이전 단계로 되돌아가 다른 경로를 탐색 + * 시간복잡도: O(N^T) (N: candidates 배열의 길이, T: target) + */ + +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +var combinationSum = function (candidates, target) { + const result = []; + + /** + * start: 현재 탐색을 시작할 배열의 인덱스 + * target: 남은 목표 합계 + * currCombination: 현재까지 선택한 숫자들의 배열 + */ + const backtrack = (start, target, currCombination) => { + if (target === 0) { + // target을 정확히 맞춘 경우(target이 0인 경우) result에 추가 + result.push([...currCombination]); + return; + } + if (target < 0) { + // target이 0보다 작은 경우 빠른 종료 + return; + } + for (let i = start; i < candidates.length; i++) { + currCombination.push(candidates[i]); // 현재 숫자 추가 + backtrack(i, target - candidates[i], currCombination); // 재귀 호출로 다음단계 진행 + currCombination.pop(); // 현재 숫자 제거 (백트래킹) 후 다음 숫자 탐색 + } + }; + backtrack(0, target, []); // 초기 호출(백트래킹 시작) + return result; +}; diff --git a/decode-ways/clara-shin.js b/decode-ways/clara-shin.js new file mode 100644 index 000000000..57fe880a4 --- /dev/null +++ b/decode-ways/clara-shin.js @@ -0,0 +1,35 @@ +/** + * 숫자 문자열이 주어졌을 때, 이를 알파벳으로 해독할 수 있는 방법의 수를 구하기 + * + * 다이나믹 프로그래밍(DP) + * (1)각 위치에서 시작하여 문자열을 해독하는 방법의 수를 계산 + * (2)중복 계산을 피하기 위해 DP를 사용 + */ + +/** + * @param {string} s + * @return {number} + */ +var numDecodings = function (s) { + if (s.length === 0 || s[0] === '0') return 0; + + const dp = new Array(s.length + 1).fill(0); + + dp[0] = 1; + dp[1] = s[0] !== '0' ? 1 : 0; + + for (let i = 2; i <= s.length; i++) { + // 한 자리 숫자로 해독하는 경우 (현재 숫자가 1-9) + if (s[i - 1] !== '0') { + dp[i] += dp[i - 1]; + } + + // 두 자리 숫자로 해독하는 경우 (10-26) + const twoDigit = parseInt(s.substring(i - 2, i)); + if (twoDigit >= 10 && twoDigit <= 26) { + dp[i] += dp[i - 2]; + } + } + + return dp[s.length]; +}; diff --git a/maximum-subarray/clara-shin.js b/maximum-subarray/clara-shin.js new file mode 100644 index 000000000..97a144277 --- /dev/null +++ b/maximum-subarray/clara-shin.js @@ -0,0 +1,24 @@ +/** + * 최대 부분 배열 합(Maximum Subarray) 또는 카데인 알고리즘(Kadane's Algorithm) + * 정수 배열이 주어졌을 때, 합이 최대가 되는 연속된 부분 배열을 찾아 그 합을 반환하는 문제 + * + * DP를 사용하여 현재 위치까지의 부분합을 계산하고, 그 중 최대값을 갱신하는 방식으로 해결 + */ + +/** + * @param {number[]} nums + * @return {number} + */ +var maxSubArray = function (nums) { + if (nums.length === 0) return 0; // 배열이 비어있으면 0 반환 + let maxSum = nums[0]; // 최대 부분합을 저장 + let currentSum = 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/number-of-1-bits/clara-shin.js b/number-of-1-bits/clara-shin.js new file mode 100644 index 000000000..f3a5b5081 --- /dev/null +++ b/number-of-1-bits/clara-shin.js @@ -0,0 +1,24 @@ +/** + * 숫자를 이진수로 변환하고 1의 개수를 세는 방법 + * Follow up: 이 함수가 여러 번 호출된다면? + * + * 단순히 모든 비트를 확인하는 방법: O(log n) 또는 32비트 정수의 경우 O(32)의 시간 복잡도 + * ➡️ Brian Kernighan의 알고리즘: O(k) + * 1 비트의 수에 비례하여 실행 시간이 결정 + */ + +/** + * @param {number} n + * @return {number} + */ +var hammingWeight = function (n) { + let count = 0; + + while (n !== 0) { + // n & (n-1)은 n의 마지막 1 비트를 제거 + n = n & (n - 1); + count++; + } + + return count; +}; diff --git a/valid-palindrome/clara-shin.js b/valid-palindrome/clara-shin.js new file mode 100644 index 000000000..07968d704 --- /dev/null +++ b/valid-palindrome/clara-shin.js @@ -0,0 +1,50 @@ +/** + * 문자열이 팰린드롬인지 확인하는 함수 + * 팰린드롬 판단: + * 대문자를 소문자로 변환 + * 영숫자(알파벳이랑 숫자)만 남기고 나머지 제거 => 정규식 알면 편함 + * 앞에서 읽으나 뒤에서 읽으나 같아야 함 + */ + +/**정규식 없이 문자열 뒤집는 방법 + * @param {string} s + * @return {boolean} + */ +var isPalindrome = function (s) { + s = s.toLowerCase(); + + let str = ''; // 영숫자만 남길 문자열 + for (let i = 0; i < s.length; i++) { + const char = s[i]; + // 알파벳이거나 숫자면 str에 추가 + if ((char >= 'a' && char <= 'z') || (char >= '0' && char <= '9')) { + str += char; + } + } + + // 문자열 뒤집기 + let reversedStr = str.split('').reverse().join(''); + + return str === reversedStr; +}; + +/**정규식 사용한 투 포인터 방법 + * @param {string} s + * @return {boolean} + */ +var isPalindrome2 = function (s) { + const str = s.toLowerCase().replace(/[^a-z0-9]/g, ''); // 영숫자만 남기 + + // 투 포인터 + let left = 0; + let right = str.length - 1; + + while (left < right) { + if (str[left] !== str[right]) { + return false; + } + left++; + right--; + } + return true; +};