diff --git a/contains-duplicate/mmyeon.js b/contains-duplicate/mmyeon.js new file mode 100644 index 000000000..9af2a45e3 --- /dev/null +++ b/contains-duplicate/mmyeon.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ + +/** + * + * 접근 방법 + * - Set 객체 사용해서 숫자 중복 제거하기 + * - 원본 배열과 길이 비교하기 + * + * 시간복잡도 : + * - 배열 순회해서 요소 Set에 삽입 : O(n) + * - Set의 사이즈 크기 비교 : O(1) + * + * 공간복잡도 : + * - Set에 유니크한 숫자 저장 : O(n) + */ + +var containsDuplicate = function (nums) { + return new Set(nums).size !== nums.length; +}; diff --git a/house-robber/mmyeon.js b/house-robber/mmyeon.js new file mode 100644 index 000000000..0e4aff237 --- /dev/null +++ b/house-robber/mmyeon.js @@ -0,0 +1,34 @@ +/** + * + * 접근 방법 : dp 사용 + * - 배열 길이가 1개 일때는 첫 번쨰 값 리턴하고, 2개면 더 큰 수를 리턴한다. + * - 3개 부터는 바로 옆집 값에 현재집 값을 더한 값과 옆옆집의 값을 비교해서 큰 값을 계산한다. + * - 다음 집 값에 현재까지의 값 활용하기 위해서, 바로 옆집, 옆옆집 값을 업데이트해준다. + * - 현재 값이 저장된 옆집값을 리턴한다. + * + * 시간복잡도 : + * - 주어진 숫자 배열 길이만큼 1회 순회하니까 O(n) + * + * 공간복잡도 : + * - 옆집과 옆옆집 값을 2개의 변수에 저장해야하니까 O(1) + * + */ +/** + * @param {number[]} nums + * @return {number} + */ +var rob = function (nums) { + if (nums.length === 1) return nums[0]; + if (nums.length === 2) return Math.max(nums[0], nums[1]); + + let prevPrevHouse = nums[0]; + let prevHouse = Math.max(nums[0], nums[1]); + + for (let i = 2; i < nums.length; i++) { + const current = Math.max(prevHouse, prevPrevHouse + nums[i]); + prevPrevHouse = prevHouse; + prevHouse = current; + } + + return prevHouse; +}; diff --git a/longest-common-subsequence/mmyeon.js b/longest-common-subsequence/mmyeon.js new file mode 100644 index 000000000..bc9dfcc47 --- /dev/null +++ b/longest-common-subsequence/mmyeon.js @@ -0,0 +1,46 @@ +/** + * + * 접근 방법 : + * - 중복 숫자 제거한 뒤, 숫자 순회하면서 연속 숫자의 시작 지점인지 체크 + * - 더 작은 숫자가 없으면 현재 숫자가 연속 숫자의 시작 지점이기 때문에, 연속된 다음 큰 숫자가 존재하는지 체크 + * - 있으면 count 증가시키고, 그 다음 숫자 있는지 반복해서 체크 + * - 연속 숫자가 존재하지 않을 때까지 순회하기 + * - count가 maxCount보다 큰 경우 maxCount값을 count 값으로 업데이트 + * + * 시간복잡도 : + * - 숫자 배열 길이를 모두 순회하니까 O(n) + * + * 공간복잡도 : + * - Set을 사용해서 숫자 중복 제거하고 저장하니까 O(n) + */ + +/** + * @param {number[]} nums + * @return {number} + */ +var longestConsecutive = function (nums) { + // 배열 비어있는 경우 처리 + if (nums.length === 0) return 0; + + const uniqueNums = new Set(nums); + let maxCount = 1; + + for (const num of uniqueNums) { + // 연속된 숫자의 시작 지점인지 체크(더 작은 숫자가 존재하지 않아야 함) + if (!uniqueNums.has(num - 1)) { + let next = num + 1; + let count = 1; + + // 연속 숫자가 더 존재하는지 체크 + while (uniqueNums.has(next)) { + next++; + count++; + } + + // 기존 maxCount보다 크면, count 값으로 업데이트하기 + if (maxCount < count) maxCount = count; + } + } + + return maxCount; +}; diff --git a/top-k-frequent-elements/mmyeon.js b/top-k-frequent-elements/mmyeon.js new file mode 100644 index 000000000..7fdce1cb1 --- /dev/null +++ b/top-k-frequent-elements/mmyeon.js @@ -0,0 +1,33 @@ +/** + * 접근 방법 : + * - 숫자 바열을 전체 순회하면서 빈도수를 객체에 저장 + * - 객체 값을 내림차순으로 정렬한 뒤, 원하는 항목만큼 자르고 숫자로 변환한 뒤 리턴하기 + * + * 시간복잡도 : O(nlogn) + * - 숫자 배열 길이 = n , 가져올 항목 개수 = k + * - 객체에 숫자와 빈도수 저장하기 위해서 모든 숫자 순회 : O(n) + * - 객체 키값을 내림차순으로 정렬 : O(nlogn) + * - slice, map : O(k) + * + * 공간복잡도 : + * - 숫자 배열의 길이만큼 객체에 저장하니까 O(n) + */ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ + +var topKFrequent = function (nums, k) { + const obj = {}; + + for (const num of nums) { + obj[num] = (obj[num] ?? 0) + 1; + } + + return Object.entries(obj) + .sort((a, b) => b[1] - a[1]) + .slice(0, k) + .map((item) => Number(item[0])); +}; diff --git a/valid-palindrome/mmyeon.js b/valid-palindrome/mmyeon.js new file mode 100644 index 000000000..857ef635f --- /dev/null +++ b/valid-palindrome/mmyeon.js @@ -0,0 +1,45 @@ +/** + * + * 접근 방법 : + * - 문자열 순회하면서 소문자로 변경한 뒤, 정규식을 이용해 알파벳과 숫자만 추출 + * - 추출된 문자에 투 포인터 사용해서 앞뒤 문자 같은지 비교. + * - 다르면 false 바로 리턴하고, 끝까지 같으면 true 반환 + * + * 시간복잡도 : + * - 문자열 길이가 n일 때, O(n) + * - match로 문자열 체크 : O(n) + * - 투 포인터로 앞뒤 문자 비교 : O(n) + * + * 공간복잡도 : + * - 최악의 경우 모든 문자가 알파벳이거나 숫자인 경우 길이가 n이 됨 : O(n) + * + * 배운 점 : + * - 문자값 필요한 게 아니니까 불필요한 배열 변환(reverse) 줄이기 + * - 문자열이 조건 범위에 부합하는지 체크할 때는 정규식 활용하기 + */ + +/** + * @param {string} s + * @return {boolean} + */ + +var isPalindrome = function (s) { + const alphanumericCharacters = s.toLowerCase().match(/[a-z0-9]/g) || []; + + let leftPointer = 0; + let rightPointer = alphanumericCharacters.length - 1; + + while (leftPointer < rightPointer) { + if ( + alphanumericCharacters[leftPointer] !== + alphanumericCharacters[rightPointer] + ) { + return false; + } + + leftPointer++; + rightPointer--; + } + + return true; +};