diff --git a/contains-duplicate/grapefruitgreentealoe.js b/contains-duplicate/grapefruitgreentealoe.js new file mode 100644 index 000000000..2bd26ce0a --- /dev/null +++ b/contains-duplicate/grapefruitgreentealoe.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ + +/** + * 문제설명: 2개 이상 반복되는 값이 있으면 true, 모두 반복되지 않으면 false. + +제한사항 + 1 <= nums.length <= 10^5 +-109 <= nums[i] <= 109 + */ + +var containsDuplicate = function (nums) { + const numberSet = new Set(); + //시간 복잡도 O(n) + for (let i of nums) { + if (!numberSet.has(i)) { + //공간복잡도 O(n) + numberSet.add(i); + } else { + return true; + } + } + return false; +}; diff --git a/house-robber/grapefruitgreentealoe.js b/house-robber/grapefruitgreentealoe.js new file mode 100644 index 000000000..fd7148257 --- /dev/null +++ b/house-robber/grapefruitgreentealoe.js @@ -0,0 +1,45 @@ +/** + * 도둑이 각 집에 돈의 양이 있는데, 근접한 집은 연결된 보안 시스템이 있다 + * 두 근접 집이 같은 밤에 강도당하면 경찰에게 연락감 + * 오늘 경찰에게 연락이 가지 않으면서 훔칠 수 있는 최대 돈 리턴 + */ + +/** + * 만약 dfs로 구한다면, 시간복잡도는 2^n이 된다 + */ +/** + * @param {number[]} nums + * @return {number} + */ + +//최대값 즉 최적의 해를 구하는 문제. dp를 활용해보자. +var rob = function (nums) { + //배열 크기가 늘어남에 따라, 작은 배열에 대한 결과를 활용하여 계산하는 아이디어. + const dp = new Array(nums.length + 1); //공간복잡도 O(n) + /** + dp[0] = 0; //하나도 없을떄 + dp[1] = nums[0]; //집이 한곳일때 + dp[2] = Math.max(dp[1], nums[1]); //집이 한곳일때의 dp값과, 현재 순번의 돈 + dp[3] = Math.max(dp[2], dp[1] + nums[2]);// 더하지 않으면 이전 결과값, 더하려면 그 전의 결과값에 더하기 + */ + for (let i = 2; i < dp.length; i++) { + //시간복잡도 O(n) + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1]); + } + return dp[dp.length - 1]; +}; + +var rob2 = function (nums) { + //배열에 저장하지 않고 변수에 바로 담는 방식 + let prev = 0; + let curr = 0; + for (let num of nums) { + //prev는 이전의 curr값으로, curr값은 이전의 prev + num + let tempPrev = prev; + prev = curr; + curr = Math.max(num + tempPrev, curr); + } + return curr; +}; +//공간복잡도를 O(1)로 개선 + diff --git a/longest-consecutive-sequence/grapefruitgreentealoe.js b/longest-consecutive-sequence/grapefruitgreentealoe.js new file mode 100644 index 000000000..7b142a0ee --- /dev/null +++ b/longest-consecutive-sequence/grapefruitgreentealoe.js @@ -0,0 +1,30 @@ +/** + * 정수 배열 nums + * 가장 많이 연속되는 요소의 길이 리턴. + * O(n) 시간안에 돌아가는 알고리즘 사용할것. + */ +/** + * @param {number[]} nums + * @return {number} + */ +var longestConsecutive = function (nums) { + const numSet = new Set(nums); + let maxCount = 0; + for (let i of numSet) { + //n 번 순회 + // ++ 이전에 연속체크가 되었을 수 있으므로, 이전 숫자가 존재한다면 pass + if (numSet.has(i - 1)) continue; //이미 진행 된 연속체크의 경우 하지 않는다. + //연속이 되는지 확인해서 있으면 1추가. + let length = 0; + while (numSet.has(i + length)) { + //연속이 끊기는 순간 멈추는 반복문. 즉 for문 전체 통틀어 최대 n번 실행. + length++; + } + maxCount = Math.max(length, maxCount); + } + return maxCount; +}; + +//시간복잡도 O(n) + O(n) = O(n) /공간복잡도 O(n) + +//생각할 지점. 양쪽으로 진행된다면, 시간복잡도 최적화 가능 diff --git a/top-k-frequent-elements/grapefruitgreentealoe.js b/top-k-frequent-elements/grapefruitgreentealoe.js new file mode 100644 index 000000000..29981ee40 --- /dev/null +++ b/top-k-frequent-elements/grapefruitgreentealoe.js @@ -0,0 +1,29 @@ +/** + * 정수 array nums , 정수 k가 있을때, 가장 빈도가 높은 숫자 k개 리턴. 순서상관 X + */ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ + +//nums에 대해서 각 요소에 대해 중복되는 횟수를 구한다. 그리고 내림차순으로 k개 리턴한다. + +var topKFrequent = function (nums, k) { + const numsFreqMap = new Map(); // O(1) + + // O(n) 시간 / O(n) 공간 + for (let num of nums) { + numsFreqMap.set(num, (numsFreqMap.get(num) ?? 0) + 1); + } + + const arrFromFreqMap = [...numsFreqMap]; // O(n) 시간 / O(n) 공간 + arrFromFreqMap.sort((a, b) => b[1] - a[1]); // O(n log n) 시간 + + return arrFromFreqMap + .map((x) => x[0]) // O(n) 시간 / O(n) 공간 + .slice(0, k); // O(k) 시간 / O(k) 공간 +}; + +//O(n) + O(n log n) + O(n) + O(k) = O(n log n) diff --git a/two-sum/grapefruitgreentealoe.js b/two-sum/grapefruitgreentealoe.js new file mode 100644 index 000000000..cce88588a --- /dev/null +++ b/two-sum/grapefruitgreentealoe.js @@ -0,0 +1,50 @@ +/** + * 정수 숫자 배열과 정수 target + * 숫자 합이 target과 같은 두 숫자의 index를 리턴. + * 같은 요소 두번 X. 답은 항상 1개 + * 정렬필요 X + */ + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function (nums, target) { + //순회. target에서 nums[i]를 뺀 요소를 찾기. + //2중포문. 시간복잡도 O(1)~O(N^2) + for (let i = 0; i < nums.length; i++) { + const subNum = target - nums[i]; // 공간 O(1) + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] == subNum) { + return [i, j]; + } + } + } +}; + +var twoSum2 = function (nums, target) { + for (let i = 0; i < nums.length; i++) { + //시간복잡도 O(N) + const subNum = target - nums[i]; // 공간 O(1) + if (nums.includes(subNum) && nums.indexOf(subNum) !== i) { + //시간복잡도 O(N). 2중포문과 같은 효과. + return [i, nums.indexOf(subNum)]; + } + } +}; + +//Better answer +var twoSum3 = function (nums, target) { + // map으로 관리하여 indexing 최적화 + const numMap = new Map(); + for (let i = 0; i < nums.length; i++) { + //시간복잡도 O(N) + const subNum = target - nums[i]; + if (numMap.has(subNum)) { + //시간복잡도 O(1) + return [i, numMap.get(subNum)]; + } + numMap.set(nums[i], i); // 공간 O(1) + } +};