-
-
Notifications
You must be signed in to change notification settings - Fork 195
[JANGSEYEONG] WEEK 01 solutions #1162
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
c4c996e
1d2501f
bfd3322
cbd7d6e
7c26233
339053b
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,14 @@ | ||
/* | ||
시간복잡도: O(n) - new Set(nums)에서 배열 요소 순회하며 Set 생성 O(n) + 길이 비교 O(1) | ||
- Set 자료구조는 중복된 값을 자동으로 제거 | ||
*/ | ||
|
||
/** | ||
* @param {number[]} nums | ||
* @return {boolean} | ||
*/ | ||
var containsDuplicate = function (nums) { | ||
// Set으로 만들었을 때, 기존 배열과 사이즈가 다르면 중복이 제거된거임 | ||
const numsSet = new Set(nums); | ||
return nums.length !== numsSet.size; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* 시간복잡도: O(n) - 배열을 한 번만 순회 | ||
* 공간복잡도: O(n) - 길이가 n+1인 DP 배열 사용 | ||
* | ||
* @param {number[]} nums | ||
* @return {number} | ||
*/ | ||
var rob = function (nums) { | ||
// arr[i] = i번째 집부터 마지막 집까지 고려했을 때 훔칠 수 있는 최대 금액 | ||
const arr = new Array(nums.length + 1); | ||
|
||
// 존재하지 않는 집(n+1번째)은 0, 점화식을 위한 계산용 공간임 | ||
arr[nums.length] = 0; | ||
|
||
// 마지막 집만 고려하면 그 집의 금액이 최대값 (이후 집들은 없으니까 0으로 계산한 결과) | ||
arr[nums.length - 1] = nums[nums.length - 1]; | ||
|
||
// 뒤에서부터 계산 | ||
for (let i = nums.length - 2; i >= 0; i--) { | ||
// i번째 집에서의 결정: | ||
// 1. i번째 집을 털고 (i+2)번째 집부터 훔치는 경우: nums[i] + arr[i+2] | ||
// 2. i번째 집을 털지 않고 (i+1)번째 집부터 훔치는 경우: arr[i+1] | ||
// 두 가지 중 최대값을 선택 | ||
arr[i] = Math.max(nums[i] + arr[i + 2], arr[i + 1]); | ||
} | ||
|
||
// arr[0]은 0번째 집부터 고려했을 때 훔칠 수 있는 최대 금액 | ||
return arr[0]; | ||
}; | ||
|
||
/* 풀이 설명: | ||
* 문제의 핵심: 인접한 집은 연속해서 털 수 없을 때 최대로 털 수 있는 금액 찾기 | ||
* | ||
* 접근 방식: 다이나믹 프로그래밍 | ||
* | ||
* 1. 상태 정의: | ||
* - f(n) = n번째 집부터 마지막 집까지 고려했을 때 털 수 있는 최대 금액 | ||
* | ||
* 2. 점화식 도출: | ||
* - 각 집마다 두 가지 선택이 있음: | ||
* 1) 현재 집을 털기: 현재 집의 돈 + 두 집 이후부터의 최대 금액 | ||
* 2) 현재 집을 털지 않기: 다음 집부터의 최대 금액 | ||
* - 따라서 점화식: f(n) = max(nums[n] + f(n+2), f(n+1)) | ||
* | ||
* 3. 베이스 케이스: | ||
* - 존재하지 않는 집: f(n+1) = 0 | ||
* - 마지막 집: f(n) = nums[n] | ||
* | ||
* 4. 계산 방향: | ||
* - 뒤에서부터 앞으로 계산 (Bottom-up) | ||
* - 마지막 집부터 시작해서 첫 번째 집까지 각 위치에서의 최대 금액 계산 | ||
* | ||
* 예시 [1,2,3,1]: | ||
* - f(4) = 0 (존재하지 않는 집) | ||
* - f(3) = 1 (마지막 집) | ||
* - f(2) = max(3 + f(4), f(3)) = max(3 + 0, 1) = 3 | ||
* - f(1) = max(2 + f(3), f(2)) = max(2 + 1, 3) = 3 | ||
* - f(0) = max(1 + f(2), f(1)) = max(1 + 3, 3) = 4 | ||
* - 결과: 4 (최적의 선택은 0번째와 2번째 집 털기) | ||
*/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
시간복잡도: O(n) - 모든 요소에 대해 최대 한 번씩만 검사하기 때문 | ||
- Set을 사용하여 O(1) 시간에 요소 존재 여부 확인 가능 | ||
- 각 숫자는 연속 수열의 시작점인 경우에만 while 루프를 실행 | ||
-> 모든 요소에 대해 while 루프의 총 반복 횟수는 전체 요소 수를 초과하지 않음 | ||
*/ | ||
/** | ||
* @param {number[]} nums | ||
* @return {number} | ||
*/ | ||
|
||
var longestConsecutive = function (nums) { | ||
const numSet = new Set(nums); | ||
let longest = 0; | ||
|
||
for (let n of [...numSet]) { | ||
if (!numSet.has(n - 1)) { | ||
let length = 0; | ||
while (numSet.has(n + length)) { | ||
length += 1; | ||
} | ||
longest = Math.max(length, longest); | ||
} | ||
} | ||
return longest; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
시간복잡도: O(n) - 배열을 두 번 순회하지만 여전히 선형 | ||
배열에서 0의 개수에 따라 결과가 달라지는 점을 이용 | ||
- 0이 두 개 이상: 모든 결과는 0 | ||
- 0이 하나: 0 위치만 전체곱, 나머지는 0 | ||
- 0이 없음: 전체곱 ÷ 현재 원소 | ||
*/ | ||
|
||
/** | ||
* @param {number[]} nums | ||
* @return {number[]} | ||
*/ | ||
var productExceptSelf = function (nums) { | ||
// 0이 있는 위치들 체크용 | ||
const zeros = new Map(); | ||
|
||
// 전체 곱 구하기 - O(n) | ||
const allProductExceptZero = nums.reduce((acc, x, i) => { | ||
if (x === 0) zeros.set(i, true); | ||
return x !== 0 ? acc * x : acc; | ||
}, 1); | ||
|
||
// 배열 전체 돌면서 조건에 맞게 return 시키기 - O(n) | ||
return nums.map((x, i) => { | ||
// 0이 2개 이상이라면 무조건 0 | ||
if (zeros.size > 1) { | ||
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. (이미 빠른 코드이지만) 전체곱을 구하는 reduce에서 0의 개수를 미리 카운트 해놓으면 0이 2개 이상인경우 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. 아 그러네요 !! 0개일 땐 위에서 미리 return 시켜도 무방한 코드인데 map 돌면서 조건 하나하나 분기하면서 생각하다보니 넣어버린 것 같습니다 ㅎㅎ.. 리뷰 감사합니다! |
||
return 0; | ||
} | ||
|
||
// 0이 1개일 때 | ||
if (zeros.size === 1) { | ||
// 그게 나일 때 | ||
if (zeros.has(i)) return allProductExceptZero; | ||
|
||
// 그게 다른애일 때 | ||
return 0; | ||
} | ||
|
||
// 0이 없을 때 | ||
return allProductExceptZero / x; | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
시간복잡도: O(n²) | ||
- nums.indexOf()는 배열 전체를 순회하는 O(n) 작업 | ||
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. O(n^2) 복잡도로는 시간초과가 나는지 궁금합니다..! 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. 리트코드에서는 시간 초과가 안납니다! O(n²)일 떄: 75ms, O(n)일 때: 2ms 로 차이가 굉장히 많이 나는건 확인했습니다 ㅎ_ㅎ 문제 하단에 "Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?" 라고 되어있어서 더 줄여봤습니다! |
||
- 이 작업이 for 루프(O(n)) 내부에서 실행되므로 전체 시간복잡도는 O(n) * O(n) = O(n²) | ||
|
||
var twoSum = function (nums, target) { | ||
for (let i = 0; i < nums.length; i++) { | ||
let x = nums.indexOf(target - nums[i]); | ||
if (x > -1 && x !== i) { | ||
return [i, x]; | ||
} | ||
} | ||
return []; | ||
}; | ||
|
||
*/ | ||
|
||
/* | ||
시간복잡도: O(n) - 전체 배열을 한 번만 순회 O(n) + 키-값 쌍 저장에 O(1) | ||
- Map 대신 객체(Object)를 사용해도 될듯 함 | ||
- 일반 객체는 {}, 접근은 obj[key]로 가능, has() 대신 (key in obj) 또는 obj[key] !== undefined 또는 key in obj 사용 가능 */ | ||
/** | ||
* @param {number[]} nums | ||
* @param {number} target | ||
* @return {number[]} | ||
*/ | ||
var twoSum = function (nums, target) { | ||
let minus = new Map(); | ||
for (let i = 0; i < nums.length; i++) { | ||
let current = nums[i]; | ||
|
||
// 현재 숫자가 이전에 저장된 보수(complement)와 일치하는지 확인 - Map 객체의 has는 O(1) 연산 | ||
if (minus.has(current)) { | ||
return [minus.get(current), i]; | ||
} | ||
|
||
// 현재 숫자의 보수(target-current)와 인덱스를 맵에 저장 - Map 객체의 set은 O(1) 연산 | ||
minus.set(target - current, i); | ||
} | ||
|
||
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.
시간, 공간복잡도를 모두 잡은 코드네요 👍👍