diff --git a/combination-sum/seongmin36.js b/combination-sum/seongmin36.js new file mode 100644 index 000000000..4db5a341c --- /dev/null +++ b/combination-sum/seongmin36.js @@ -0,0 +1,43 @@ +/** +백트래킹(backtracking)을 이용한 풀이 + +candidates 배열이 순차 정렬을 위해 오름차순으로 정렬한다. +함수 파라미터는 backtracking(남은 수, 현재 push된 배열, 탐색한 인덱스)를 받는다. + +동작 원리 +1. candidates의 작은 원소부터 하나씩 push하고, 해당 원소를 target에서 차감한다 → remains +2. dfs 방식으로 재귀적으로 호출하여 remains가 0이 되면 최종 result 배열에 push된다. +3. 여기서 breakpoint는 탐색 인덱스의 값이 remains보다 큰 경우이다. +4. 가장 핵심인 부분은 원본 배열에 find_number/remains를 조합할 수 없으면 pop()을 호춣하는데, +이는 진행중인 단계에서 더 이상의 조합을 찾지 못해서 다음 조합을 찾기 위한 필수 과정이다. + */ +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +function combinationSum(candidates, target) { + let result = []; + + candidates.sort((a, b) => a - b); + + function backtracking(remains, current, index) { + if (remains === 0) { + result.push([...current]); + } + + for (let i = index; i < candidates.length; i++) { + let find_number = remains - candidates[i]; + + if (candidates[i] > remains) break; + + current.push(candidates[i]); + backtracking(find_number, current, i); + current.pop(); + } + } + + backtracking(target, [], 0); + + return result; +} diff --git a/decode-ways/seongmin36.js b/decode-ways/seongmin36.js new file mode 100644 index 000000000..21e3c7ab6 --- /dev/null +++ b/decode-ways/seongmin36.js @@ -0,0 +1,47 @@ +/** +검증해야되는 케이스는 총 2가지다. +1. 1~9까지의 알파벳 +2. 10~26까지의 알파벳 + +우선 맨 앞자리가 '0'인 경우는 항상 0을 반환하도록 한다. +substring() 메서드를 활용하여 s로부터 특정 범위의 string을 가져와야 한다. +1자리일 때(one_char), 2자리일 때(two_char) 케이스를 비교한다. + +중요한 점은 '비교한 값은 어떻게 저장해야하는가?'이다. +여러 방법이 있지만, 'climbing stairs'(피보나치 수열)에서 사용했던 '바텀업 방식의 DP'를 사용한다. +바텀업 DP를 사용하는 이유는 두 가지의 케이스의 합을 기억하고 더한 값을 가져와야하기 때문이다. + */ + +/** + * @param {string} s + * @return {number} + */ +function numDecodings(s) { + if (s[0] === "0") return 0; + + let dp = new Array(s.length + 1).fill(0); + + dp[0] = 1; + + function isAlphabet(str) { + if (str.length === 1) return str >= "1" && str <= "9"; + if (str.length === 2) return str >= "10" && str <= "26"; + + return false; + } + + for (let i = 1; i < dp.length; i++) { + let one_char = s.substring(i - 1, i); + let two_char = s.substring(i - 2, i); + + if (isAlphabet(one_char)) { + dp[i] += dp[i - 1]; + } + if (i >= 2) { + if (isAlphabet(two_char)) { + dp[i] += dp[i - 2]; + } + } + } + return dp[s.length]; +} diff --git a/maximum-subarray/seongmin36.js b/maximum-subarray/seongmin36.js new file mode 100644 index 000000000..ddd6c255c --- /dev/null +++ b/maximum-subarray/seongmin36.js @@ -0,0 +1,26 @@ +/** +이 문제의 핵심은 연결된 배열이어야 하고, 누적된 값의 합이 음수라면 과감하게 다시 시작하는 것이다. +이를 카데인 알고리즘(Kadane's Algorithm)이라고 한다. + */ + +/** + * @param {number[]} nums + * @return {number} + */ +function maxSubArray(nums) { + let result = nums[0]; + let cur_sum = nums[0]; + + if (nums.length === 1) return nums[0]; + + for (let i = 1; i < nums.length; i++) { + if (cur_sum <= 0) { + cur_sum = nums[i]; + } else if (cur_sum > 0) { + cur_sum = cur_sum + nums[i]; + } + + result = Math.max(result, cur_sum); + } + return result; +} diff --git a/number-of-1-bits/seongmin36.js b/number-of-1-bits/seongmin36.js new file mode 100644 index 000000000..f10254aa0 --- /dev/null +++ b/number-of-1-bits/seongmin36.js @@ -0,0 +1,24 @@ +/** +toString(2)으로 해결했다가 다른 분의 풀이를 보고 다시 풀어보았다. + +'비트 연산을 통한 계산'이다. +컴퓨터에서 모든 언어는 2진법으로 변환이 되는데, 이를 이용한 플이다. +가장 오른쪽 비트가 1인 경우에 count++, n을 우측으로 1칸 shift. +shift를 하면 결국 남는 숫자는 0이기 때문에 적절한 조건으로 루프를 빠져나온다. + +굳이 2진법으로 변환하지 않고도 계산할 수 있어서 이게 더 좋은 풀이라 생각하였다. + */ +/** + * @param {number} n + * @return {number} + */ +function hammingWeight(n) { + let count = 0; + + while (n !== 0) { + count += n & 1; + n >>>= 1; + } + + return count; +} diff --git a/valid-palindrome/seongmin36.js b/valid-palindrome/seongmin36.js new file mode 100644 index 000000000..dedd19fc6 --- /dev/null +++ b/valid-palindrome/seongmin36.js @@ -0,0 +1,27 @@ +/** +s를 정규식으로 알파벳 소문자 string만 남겨둬야한다. +알파벳 소문자만 남겨놓도록 하는 정규식은 '/[^a-z0-9]/gi'이다. +left(0)와 right(마지막 인덱스)를 동시에 하나씩 줄여가면서 비교 + */ + +/** + * @param {string} s + * @return {boolean} + */ +function isPalindrome(s) { + s = s.replace(/[^a-z0-9]/gi, "").toLowerCase(); + + let left = 0; + let right = s.length - 1; + + while (left < right) { + if (s[left] !== s[right]) { + return false; + } + + left++; + right--; + } + + return true; +}