-
-
Notifications
You must be signed in to change notification settings - Fork 248
[yoouyeon] WEEK 01 solutions #1179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
900d301
6f8cc1a
ba7602e
b1436f3
287b005
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* Solution 1. Set을 활용하기 1 | ||
* | ||
* [Idea] | ||
* nums에서 중복된 원소를 제거하기 위해서 nums를 이용해서 중복을 허용하지 않는 자료구조인 Set을 생성 (numSet) | ||
* 중복된 원소가 있었다면 set을 생성할 때 제거되어 nums의 길이와 numSet의 크기가 다를 것이므로 비교해서 결과를 반환 | ||
* | ||
* [Time Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* nums 배열을 이용해서 Set을 만드는 것에서 O(n) | ||
* | ||
* [Space Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* numSet을 생성하기 위해 최대 n만큼의 공간이 추가로 필요함 | ||
*/ | ||
function containsDuplicate1(nums: number[]): boolean { | ||
const numsSet = new Set<number>(nums); | ||
return numsSet.size !== nums.length; | ||
} | ||
|
||
/** | ||
* Solution 2. Set을 활용하기 2 | ||
* | ||
* [Idea] | ||
* 최악의 경우가 아닐 때 약간 더 빠르게 결과를 반환할 수 있는 방법 | ||
* 중복인 원소를 마주하자마자 바로 반환하기 때문에 아주 조금 더 빠름 | ||
* | ||
* [Time Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* | ||
* [Space Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* 생성자로 추가하는 것과 add로 추가하는 차이 때문인지 실제로 사용된 메모리는 Solution 1보다 조금 많다. | ||
*/ | ||
Comment on lines
+31
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 당연히 early return 방식에서 사용 메모리량이 적을 줄 알고 실제로 Leetcode에서 두 코드를 돌려보았는데 정말 containsDuplicate2이 좀 더 높게 나오더군요. 궁금증이 생겨서 ChatGPT에게 물어보았는데 다음과 같은 답변을 얻었습니다! 1. LeetCode의 메모리 측정 방식은 "최대 메모리 사용량(Peak Usage)"
2. 자바스크립트 엔진(V8) 특성
3. 런타임 내부 변수 및 실행 경로의 차이
실제로는?
제가 JS를 잘 모르기도 하고 ChatGPT에만 의존한 정보여서 우선은 참고만 하시고.. 추후 더 깊게 공부해보시면 좋을 것 같습니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리뷰 감사합니다..!! 😁 GPT에게 찾아볼 생각은 못해봤네요 😅 반복자나 조건문이 메모리에 영향을 줄거라고는 생각을 못해봤어서 덕분에 공부해 볼 포인트를 더 알게 된 것 같습니다 ㅎㅎ 감사합니다 ~ ! ㅎㅎ |
||
function containsDuplicate2(nums: number[]): boolean { | ||
const numSet = new Set<number>(); | ||
|
||
for (const num of nums) { | ||
if (numSet.has(num)) { | ||
return true; | ||
} | ||
numSet.add(num); | ||
} | ||
|
||
return false; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* [Idea] | ||
* 어떤 집을 턴다고 했을 때 최대 금액을 구하는 식은 아래와 같이 세울 수 있다.: | ||
* Math.max(전 집을 털었을 때의 최대 금액, 전전 집을 털었을 때의 최대 금액 + 지금 집을 털었을 때 얻는 금액) => DP | ||
* 연산 횟수를 줄여주기 위해서 메모 배열을 이용했다. | ||
* | ||
* [Time Complexity] | ||
* O(n) | ||
* for loop 에서 nums 배열의 각 원소에 한번씩만 접근하므로 O(n) | ||
* | ||
* [Space Complexity] | ||
* O(n) | ||
* 메모 배열을 위한 추가 공간 | ||
*/ | ||
function rob(nums: number[]): number { | ||
const n = nums.length; | ||
if (n === 1) { | ||
return nums[0]; | ||
} | ||
|
||
// idx 집을 터는 경우 vs 안 터는 경우를 비교해서 큰 값을 저장하는 dp 배열 | ||
const memo = new Array(n).fill(0); | ||
memo[0] = nums[0]; | ||
memo[1] = Math.max(memo[0], nums[1]); | ||
|
||
for (let idx = 2; idx < n; idx++) { | ||
// idx번째 집에서의 최대 금액 = idx번째 집을 터는 경우 vs 안 터는 경우 중 최댓값 | ||
memo[idx] = Math.max(memo[idx - 2] + nums[idx], memo[idx - 1]); | ||
} | ||
|
||
return memo[n - 1]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* [Idea] | ||
* O(n)이기 때문에 정렬 방식은 불가능하다고 판단함. => 특별한 방법이 생각이 안나서 일일이 구간을 확인해 주는 방식을 시도했다. | ||
* 배열을 순회할 때 빠르게 원소를 찾아야 하기 때문에 Set을 이용하기로 함. | ||
* | ||
* [Time Complexity] | ||
* O(n + n) => O(n) | ||
* - Set 생성: O(n) | ||
* - for loop: O(n) | ||
* for loop 내부에 while loop가 있긴 하지만 "증가하는 구간의 시작점일 때만 실행되기 때문에" (이걸 놓쳐서 시간 초과 났었다..) | ||
* 각 원소에 접근하는 횟수는 결국 1번뿐. | ||
* | ||
* [Space Complexity] | ||
* O(n) | ||
* Set을 생성하기 위해 추가로 필요한 공간 | ||
*/ | ||
|
||
function longestConsecutive(nums: number[]): number { | ||
const numSet = new Set<number>(nums); | ||
let longest = 0; | ||
|
||
for (const startNum of numSet) { | ||
// 증가하는 구간의 시작점인 경우에만 검사한다. (같은 구간을 중복해서 탐색하는 것을 막기) | ||
// nums.length가 10000인 경우에 뜬 Time Limit Exceeded를 해결하기 위해 추가함... | ||
if (numSet.has(startNum - 1)) { | ||
continue; | ||
} | ||
let length = 1; | ||
let currNum = startNum + 1; | ||
while (numSet.has(currNum)) { | ||
length++; | ||
currNum++; | ||
} | ||
longest = Math.max(longest, length); | ||
} | ||
|
||
return longest; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* [Idea] | ||
* 숫자와 등장 횟수를 세는 counter Map을 활용했다. | ||
* 1. counter Map을 만든 뒤 | ||
* 2. 배열로 변환 | ||
* 3. count 내림차순으로 정렬 | ||
* 4. 정답 배열 만들기 | ||
* | ||
* [Time Complexity] | ||
* O(n + m log m) => O(n log n) (n: nums의 길이, m: nums에서 unique elements의 개수) | ||
* - counter Map을 생성할 때 O(n) | ||
* - counter를 배열로 변환해서 정렬할 때 O(m log m) | ||
* - sortedCounter를 k 길이로 자르고 count만 담은 배열로 만들 때 O(k) | ||
* | ||
* [Space Complexity] | ||
* O(m + k) => O(n) | ||
* - counter Map의 O(m) | ||
* - 정답 배열을 만들 때 추가로 사용하는 O(k) | ||
*/ | ||
function topKFrequent1(nums: number[], k: number): number[] { | ||
const counter = new Map<number, number>(); // key: 숫자, value: count | ||
for (const num of nums) { | ||
const count = counter.get(num); | ||
counter.set(num, count === undefined ? 1 : count + 1); | ||
} | ||
|
||
const sortedCounter = [...counter].sort((a, b) => b[1] - a[1]); | ||
return sortedCounter.slice(0, k).map((count) => count[0]); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* Solution 1. 배열에서 짝 찾기 | ||
* | ||
* [Idea] | ||
* 단순하게 nums를 순회하면서 현재 원소(num)과 합해서 target을 만들 수 있는 원소가 있는지 확인함 | ||
* | ||
* [Time Complexity] | ||
* O(n^2) (n: nums의 원소 개수) | ||
* nums를 순회하면서 (O(n)) Array.indexOf 메소드로 짝이 되는 원소를 찾는 방식 (O(n)) | ||
* O(n)이 중첩되어 있으므로 O(n^2) | ||
* | ||
* [Space Complexity] | ||
* O(1) | ||
*/ | ||
function twoSum1(nums: number[], target: number): number[] { | ||
for (let idx = 0; idx < nums.length - 1; idx++) { | ||
const complementIdx = nums.indexOf(target - nums[idx], idx + 1); | ||
if (complementIdx !== -1) { | ||
return [idx, complementIdx]; | ||
} | ||
} | ||
// 타입 에러를 제거하기 위해 추가한 코드. | ||
// 답이 무조건 존재한다는 조건이 있었으므로 이 코드에는 도달하지 않는다. | ||
return []; | ||
} | ||
|
||
/** | ||
* Solution 2. Map을 이용하기 - 1 | ||
* | ||
* [Idea] | ||
* O(n^2)보다 작게 만들 수 있는 방법은 인덱스를 찾는 데 걸리는 시간을 줄이는 것이라 생각해서 검색 시간이 짧은 Map을 활용함. | ||
* | ||
* [Time Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* Map을 생성할 때 O(n) | ||
* Map에서 짝이 되는 원소를 찾는 것은 O(1) | ||
* | ||
* [Space Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* Map을 생성할 때 필요한 공간 n | ||
*/ | ||
function twoSum2(nums: number[], target: number): number[] { | ||
const numMap = nums.reduce((map, num, idx) => { | ||
map.set(num, idx); | ||
return map; | ||
}, new Map()); | ||
|
||
for (let idx = 0; idx < nums.length; idx++) { | ||
const complementIdx = numMap.get(target - nums[idx]); | ||
if (complementIdx !== undefined && complementIdx !== idx) { | ||
return [idx, complementIdx]; | ||
} | ||
} | ||
|
||
return []; | ||
} | ||
|
||
/** | ||
* Solution 3. Map을 이용하기 - 2 | ||
* | ||
* [Idea] | ||
* Map을 미리 생성하지 않고 짝을 찾는 for loop에서 Map을 생성한다. | ||
* [a, b]가 답일 때 지금까지는 a를 기준으로 b를 찾았지만 지금은 b를 기준으로 a를 찾게 되는 것! | ||
* | ||
* [Time Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* | ||
* [Space Complexity] | ||
* O(n) (n: nums의 원소 개수) | ||
* Solution 1보다 조금 메모리를 덜 쓴다. | ||
*/ | ||
function twoSum3(nums: number[], target: number): number[] { | ||
const numMap = new Map(); | ||
|
||
for (let idx = 0; idx < nums.length; idx++) { | ||
const complementIdx = numMap.get(target - nums[idx]); | ||
if (complementIdx !== undefined) { | ||
return [idx, complementIdx]; | ||
} | ||
numMap.set(nums[idx], idx); | ||
} | ||
|
||
return []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set 자료구조를 이렇게 활용할 수도 있군요. 코드도 더 간단해지고 좋은 방법인 것 같습니다!