-
Notifications
You must be signed in to change notification settings - Fork 126
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
[pepper] Week 03 Solutions #402
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a57928c
1. two sum
whewchews 23bfc3d
2. climbing stairs
whewchews dc1b7af
3. Product of Array Except Self
whewchews f62a2c0
4. Combination Sum
whewchews ba002c4
3. Product of Array Except Self 2
whewchews 3c26ea7
5. coin change
whewchews c0d6bb0
chore: lint
whewchews b7e3dd7
fix: climb stairs logic
whewchews f16e54a
fix: TC, SC
whewchews File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* 아이디어 | ||
* 층수 제한: 1 <= n <= 45 | ||
* 1 or 2 step 만 올라갈 수 있음 | ||
* 1 -> [1] | ||
* 2 -> [1,1] [2] | ||
* 3 -> [1,1,1] [2,1] [1,2] | ||
* 4 -> [1,1,1,1] [2,1,1] [1,2,1] [1,1,2] [2,2] | ||
* 5 -> [1,1,1,1,1] [2,1,1,1] [1,2,1,1] [1,1,2,1] [1,1,1,2] [2,2,1], [1,2,2], [2,1,2] | ||
* 6 -> [1,1,1,1,1,1] [2,1,1,1,1] [...] [1,1,1,1,2] [2,2,1,1], [2,1,2,1], [2,1,1,2] [1,1,2,2], [1,2,1,2], [1,2,2,1] | ||
=> (1:n, 2:0) n가지 (1:n-2, 2:1) / n가지 (1: n-4, 2: n/2) C(n, n/2) 가지 | ||
*/ | ||
function climbStairs(n: number): number { | ||
// # Solution 1 | ||
|
||
// const stair = {1: 1, 2:2} | ||
// for(let i = 3; i<=n; i++){ | ||
// stair[i] = stair[i-1] + stair[i-2] | ||
// } | ||
// TC: O(N) | ||
// SC: O(N) | ||
|
||
// # Solution 2 | ||
|
||
// if(n < 3) return n | ||
// let curr = 2 // 현재 계단을 오르는 방법 수 | ||
// let prev = 1 // 이전 계단을 오르는 방법 수 | ||
|
||
// for(let i=0; i<n-2; i++){ | ||
// const next = prev + curr; | ||
// prev = curr; | ||
// curr = next; | ||
// } | ||
|
||
// return curr | ||
// TC: O(N) | ||
// SC: O(1) | ||
|
||
// # Solution 3: 재귀 | ||
const memo = { 1: 1, 2: 2 }; | ||
function calculateClimbingWay(n, memo) { | ||
if (n in memo) return memo[n]; | ||
|
||
if (n < 3) { | ||
return n; | ||
} | ||
memo[n] = | ||
calculateClimbingWay(n - 1, memo) + calculateClimbingWay(n - 2, memo); | ||
|
||
return memo[n]; | ||
} | ||
return calculateClimbingWay(n, memo); | ||
// TC: O(N) | ||
// SC: O(N) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
function coinChange(coins: number[], amount: number): number { | ||
/* # Solution 1: BFS | ||
* 최소 경로를 찾는 문제 => BFS | ||
* 현재까지 사용한 동전의 개수와 현재까지 사용한 동전의 합을 queue에 넣는다. | ||
* visited: 중복 방문을 방지하기 위한 set | ||
* 누적액이 amount와 같아지면 count를 return | ||
* visited에 누적액이 있으면 continue | ||
* coins를 순회하면서 누적액에 동전을 더한 값이 amount보다 작으면 queue에 넣는다. | ||
* queue가 빌때까지 반복 | ||
* 큐가 비어있고 amount를 만들수 없으면 -1을 return | ||
*/ | ||
const queue = [[0, 0]]; // [number of coins, accumulated amount] | ||
const visited = new Set(); | ||
|
||
while (queue.length > 0) { | ||
const [count, total] = queue.shift(); | ||
whewchews marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (total === amount) { | ||
return count; | ||
} | ||
if (visited.has(total)) { | ||
continue; | ||
} | ||
visited.add(total); | ||
for (const coin of coins) { | ||
if (total + coin <= amount) { | ||
queue.push([count + 1, total + coin]); | ||
} | ||
} | ||
} | ||
return -1; | ||
} | ||
// TC: 각 금액(amount)마다 동전(coins)을 순회하므로 O(N^2*M) N: amount, M: coins.length | ||
// SC: O(N) N: amount |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
function combinationSum(candidates: number[], target: number): number[][] { | ||
/* | ||
* 합이 target이 되는 candidates 경우의 수를 리턴 | ||
* cadidates는 고유함 | ||
* 합이 target이 되지 않는 경우, 빈배열 리턴 | ||
* cadidate을 중복 사용 가능 | ||
* 2 <= candidates[i] <= 40 | ||
* => candidate이 1인 경우는 없음 | ||
* candidates에서 target보다 같거나 작은 값만 filter하고 시작 (target보다 큰 값은 후보군이 될 수 없음) | ||
* | ||
* [2,3,6,7] / 7 | ||
* | ||
* [] | ||
* [2] / 5 | ||
* [2, 2] 3 => X | ||
* [2, 2, 2] 1 => X | ||
* [2, 2, 2, 2] -1 => X | ||
* [2, 2, 2, 3] -2 => X | ||
* [2, 2, 2, 6] -5 => X | ||
* [2, 2, 2, 7] -6 => X | ||
[2, 2, 3] 0 => O | ||
// ... | ||
[2, 3] 2 => X | ||
[2, 3, 2] 0 => O | ||
// ... | ||
[2, 6] -1 => X | ||
// ... | ||
* | ||
* 하나씩 값을 추가하면서 배열의 총합을 target 값과 비교한다 | ||
* sum이 target값보다 작으면 계속 다음 값을 추가해준다 | ||
* sum이 target과 같으면 결과 값 result 배열에 추가해준다. | ||
* sum이 target보다 넘으면 마지막에 추가한 값을 뺀다. | ||
* 이 과정을 반복하며 배열에서 결과 값을 찾는다. | ||
* | ||
*/ | ||
|
||
|
||
function backtrack(candidates: number[], start:number, total:number){ | ||
if(target === total){ | ||
result.push([...path]) | ||
return | ||
} | ||
|
||
if(target < total){ | ||
return | ||
} | ||
|
||
for(let i=start; i<=candidates.length-1; i++){ | ||
path.push(candidates[i]) | ||
backtrack(candidates, i,total + candidates[i]) | ||
path.pop() | ||
} | ||
} | ||
|
||
const result = [] | ||
const path = [] | ||
// TC: O(NlogN) | ||
// SC: O(N) | ||
const filteredCandidates = candidates.filter(candidate => candidate<=target).sort((a,b)=> a-b) | ||
backtrack(filteredCandidates, 0, 0) | ||
return result | ||
|
||
}; | ||
// TC: O(n^t) n = candidates.length, t = target 크기 | ||
// SC: O(t) | ||
|
||
/* #Solution 2 : DP | ||
* candidates을 가지고 target 값을 만들 수 있는 모든 조합을 미리 찾아둔다. | ||
*candidates [2,3,6,7] / target 7 라고 했을때 | ||
* 1) candidate = 2 | ||
* dp[2] = [[2]] | ||
* dp[4] = [[2,2]] | ||
* dp[6] = [[2,2,2]] | ||
* 2) candidate = 3 | ||
* dp[3] = [[3]] | ||
* dp[5] = [[2,3]] | ||
* dp[6] = [[2,2,2], [3,3]] | ||
* dp[7] = [[2,2,3]] | ||
* 3) candidate = 6 | ||
* dp[6] = [[[2,2,2], [3,3], [6]] | ||
* 4) candidate = 7 | ||
* dp[7] = [[2,2,3], [7]] | ||
* | ||
* => dp = [ | ||
* [ [] ] | ||
* [ [] ] | ||
* [ [2] ] | ||
* [[3]] | ||
* [[2,2]] | ||
* [[2,3,]] | ||
* [[2,2,2], [3,3], [6]] | ||
* [[2,2,3], [7]] | ||
* ] | ||
* ] | ||
* / | ||
|
||
|
||
|
||
// SC: O(t) t = target | ||
const dp = Array.from({ length: target + 1 }, () => []); | ||
dp[0] = [[]]; | ||
|
||
|
||
for (let candidate of candidates) { | ||
for (let i = candidate; i <= target; i++) { | ||
for (let combination of dp[i - candidate]) { | ||
dp[i].push([...combination, candidate]); | ||
} | ||
} | ||
} | ||
|
||
return dp[target]; | ||
} | ||
|
||
// TC: O(n * t * 2^n) n = candidates.length, t = target | ||
// SC: O((t*2^n) // 최악의 경우 모든 조합(2^n) 저장 가능 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* #Solution 1 | ||
* sum: 전체 곱을 구한다. | ||
* zeroCount: 0의 개수가 몇개인지 센다. | ||
* 1. 자신이 0이면, | ||
* 1-1. 자신이외의 0이 있는지 확인하고 있으면 0을 return | ||
* 1-2. 자신 이외에 0이 없으면 전체 곱을 return | ||
* 2. 자신이 0이 아니면 | ||
* 2-1. zeroCount가 있는지 보고 있으면 0을 return | ||
* 2-2. zero가 없으면 sum/self를 return | ||
* | ||
* 그러나... 문제에 나누기 연산자를 쓰면 안된다고 했으므로 Solution 2로 가자. | ||
*/ | ||
function productExceptSelf(nums: number[]): number[] { | ||
// let zeroCount = 0; | ||
// const sum = nums.reduce((p, c) => { | ||
// if (c === 0) { | ||
// zeroCount += 1; | ||
// return p; | ||
// } | ||
// p = p * c; | ||
// return p; | ||
// }, 1); | ||
|
||
// const hasZero = zeroCount > 0; | ||
|
||
// if (zeroCount === nums.length) return Array(nums.length).fill(0); | ||
|
||
// return nums.map((n) => { | ||
// if (n === 0) { | ||
// // 자신 이외에 0이 있을때 | ||
// if (zeroCount - 1 > 0) { | ||
// return 0; | ||
// } | ||
|
||
// return sum; | ||
// } | ||
|
||
// if (hasZero) return 0; | ||
// return sum / n; | ||
// }); | ||
// TC: O(N) | ||
// SC: O(N) | ||
|
||
/* #Solution 2 | ||
* 1. prefix: 자신을 제외한 자기 인덱스 앞까지의 곱을 저장한다. | ||
* 2. suffix: 자신을 제외한 자기 뒤까지의 곱을 저장한다. | ||
* 3. answer[i] = prefix[i] * suffix[i] | ||
*/ | ||
const n = nums.length; | ||
|
||
const prefix = new Array(n).fill(1); | ||
const suffix = new Array(n).fill(1); | ||
|
||
for (let i = 1; i < n; i++) { | ||
prefix[i] = prefix[i - 1] * nums[i - 1]; | ||
} | ||
|
||
for (let i = n - 2; i >= 0; i--) { | ||
suffix[i] = suffix[i + 1] * nums[i + 1]; | ||
} | ||
|
||
const answer = []; | ||
for (let i = 0; i < n; i++) { | ||
answer[i] = prefix[i] * suffix[i]; | ||
} | ||
|
||
return answer; | ||
} | ||
// TC: O(N) | ||
// SC: O(N) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* 아이디어 | ||
* 처음부터 배열을 순회하며 [0,1] [0,2] [0,3] [0, ...], [1,2], [1,3], [1,...] ... [nums.length-2, nums.length-1] 를 돌면서 두 인자의 합이 target이 되는 지점을 찾는다. | ||
* 순서대로 돌면 최악의 경우 가장 마지막 자리까지 갈 수도 있다. | ||
* 절대 값이 되지 못하는, 최소 조건을 생각해보자. | ||
* 주의1:범위가 -10^9 <= nums[i] <= 10^9로 음수값도 있음 | ||
* 주의2: 정렬된 순서가 아님. | ||
* 값을 Map에 저장해두고 {value: index}, Map에 자신과 더했을때 target이 나오는 value가 있는지 확인 | ||
*/ | ||
function twoSum(nums: number[], target: number): number[] { | ||
// SC: O(N) | ||
const dict = new Map(); | ||
|
||
// TC: O(N) | ||
for (let i = 0; i <= nums.length - 1; i++) { | ||
const curr = nums[i]; | ||
const pairValue = target - curr; | ||
if (dict.has(pairValue)) { | ||
return [dict.get(pairValue), i]; | ||
} | ||
|
||
dict.set(curr, i); | ||
} | ||
} | ||
|
||
// TC: O(N) | ||
// SC: O(N) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
안녕하세요 @whewchews 님! 사고과정을 잘 써주셔서 이해가 잘 됐습니다!
이 라인의 경우 인덱스가 숫자인 만큼 배열을 사용할수도 있을것같아요!