당신은 계단을 올라갑니다. 정상에 도달하려면 n걸음이 걸립니다.
매번 1레벨 또는 2레벨을 오를 수 있습니다. 얼마나 많은 다른 방법으로 정상에 오를 수 있습니까?
예 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
예 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
제한:
- 1<=n<=45
◇ 솔루션
먼저 무의식적으로 4의 경우의 수를 계산합니다. 5의 4와 8의 5… 그것이 피보나치입니다. 죄송해요 뒤늦게 알아 피보나치 수식을 풀 수 있는 방법이 있었는지 어렴풋이 기억이 나네요… 아니 기억이 안나네요. 어떻게 지내세요?
이런저런 글을 쓰기 시작하면서 한 가지가 분명해졌습니다. 재귀를 통해 해결하는 방법을 알아낼 수 없습니다. 재귀를 마지막으로 사용한 것이 언제인지 확실하지 않습니다. 그냥 잊으세요 그러다가 갑자기 문제가 동적 프로그래밍 범주에 있다는 것을 기억했습니다. 해결책을 찾았습니다.
- 이전 숫자 변수 제공(n이 얼마인지 모름)
- 나중에 숫자 변수를 입력하십시오.
- 우리가 찾아야 하는 n은 (n-1 더하기 n-2)입니다.
2개의 변수로만 하려고 했기 때문에 변수에 값을 할당해 보았습니다.
// 첫 번째 시도
var climbStairs = function(n) {
if (n < 4) return n
let left = 0
let right = 1
while (n > 0) {
right = right + left
left = right
n--
}
return right
};
생각의 흐름을 덜 따른 결과다. 새 값은 둘의 합이기 때문에 오른쪽 + 왼쪽이고 새 왼쪽 값에 올바른 값을 할당할 수 있지만 결과는 참담한 실패입니다.
그러고 보니 이미 새로운 가치가 부여됐죠? 왼쪽에 넣고 앉았으니 불가능할 수밖에 없었다. a+b=c의 구조에서 a와 b의 값을 알면 bc의 값은 -a가 된다.
// 통과된 답안
var climbStairs = function(n) {
if (n < 4) return n
let left = 0
let right = 1
while (n > 0) {
right = right + left
left = right - left
n--
}
return right
};
이렇게 다이나믹프로그래밍으로 문제를 해결했는데 많이 불편하네요. 다른 솔루션을 살펴보겠습니다.
1. 메모이제이션을 사용한 재귀
- 재귀와 메모이제이션을 오랜만에 보니 코드가 짧네요.
var climbStairs = function(n, memo = {1:1, 2:2}) {
if (memo(n) !== undefined) return memo(n);
memo(n) = climbStairs(n - 1, memo) + climbStairs(n - 2, memo);
return memo(n);
};
2. 재귀
- 그래 내가 그랬어 (내일이 기억나지 않는다고 했지)
function climbStairs(n) {
if (n <= 0) return 0;
if (n === 1) return 1;
if (n === 2) return 2;
return climbStairs(n - 1) + climbStairs(n - 2);
}
3. 무차별 대입(DFS) 또는 철저한 검색
- … 재귀와 동적 프로그래밍이 가능하다고 생각합니다.
/**
* Brute Force - DFS
* Time O(2^N) | Space O(N)
* https://leetcode.com/problems/climbing-stairs/
* @param {number} n
* @return {number}
*/
var climbStairs = (n, index = 0) => {
const isBaseCase1 = (n < index);
if (isBaseCase1) return 0;
const isBaseCase2 = (index === n);
if (isBaseCase2) return 1;
const ( next, nextNext ) = ( (index + 1), (index + 2) );
const left = climbStairs(n, next); /* Time O(2^N) | Space O(N) */
const right = climbStairs(n, nextNext);/* Time O(2^N) | Space O(N) */
return (left + right);
}
4. 다른 DP(위에서 아래로)
- 같은 DP, 다른 느낌
/**
* DP - Top Down
* Array - Memoization
* Time O(N) | Space O(N)
* https://leetcode.com/problems/climbing-stairs/
* @param {number} n
* @return {number}
*/
var climbStairs = (n, index = 0, memo = Array(n + 1).fill(0)) => {
const isBaseCase1 = (n < index);
if (isBaseCase1) return 0;
const isBaseCase2 = (index === n);
if (isBaseCase2) return 1;
const hasSeen = (memo(index) !== 0);
if (hasSeen) return memo(index);
const ( next, nextNext ) = ( (index + 1), (index + 2) );
const left = climbStairs(n, next, memo); /* Time O(N) | Space O(N) */
const right = climbStairs(n, nextNext, memo);/* Time O(N) | Space O(N) */
memo(index) = (left + right); /* | Space O(N) */
return memo(index);
};
5. 또 다른 DP (아래에서 위로)
- 같은 DP라도 저렇게 변합니다.
/**
* DP - Bottom Up
* Array - Tabulation
* Time O(N) | Space O(N)
* https://leetcode.com/problems/climbing-stairs/
* @param {number} n
* @return {number}
*/
var climbStairs = (n) => {
const isBaseCase = (n === 1);
if (isBaseCase) return 1;
const tabu = initTabu(n);/* Space O(N) */
search(n, tabu);
return tabu(n);
};
var initTabu = (n) => {
const tabu = new Array(n + 1).fill(0);
tabu(1) = 1;
tabu(2) = 2;
return tabu;
}
var search = (n, tabu) => {
for (let index = 3; (index <= n); index++) {/* Time O(N) */
const ( prev, prevPrev ) = ( (index - 1), (index - 2) );
tabu(index) = (tabu(prev) + tabu(prevPrev));/* Space O(N) */
}
}
6. 매트릭스 – 비트넷 방식
- ???
/**
* Matrix - Bitnets Method
* Time O(log(N)) | Space O(1)
* https://leetcode.com/problems/climbing-stairs/
* @param {number} n
* @return {number}
*/
var climbStairs = (n) => {
const prev = ( (1, 1), (1, 0) );
const next = power(n, prev);/* Time O(log(N)) */
return next(0)(0);
}
const power = (n, prev) => {
let next = ( (1, 0), (0, 1) );
const isEmpty = () => n === 0;
while (!isEmpty()) {/* Time O(log(N)) */
const isBit = (n & 1) === 1;
if (isBit) next = multiply(next, prev);/* Time O(1) | Space O(1) */
n >>= 1;
prev = multiply(prev, prev); /* Time O(1) | Space O(1) */
}
return next;
}
const multiply = (prev, next) => {
const ( rows, cols ) = ( 2, 2 );
const matrix = new Array(rows).fill()
.map(() => new Array(cols).fill(0));
for (let row = 0; (row < rows); row++) {
for (let col = 0; (col < cols); col++) {
const left = (prev(row)(0) * next(0)(col));
const right = (prev(row)(1) * next(1)(col));
matrix(row)(col) = (left + right);
}
}
return matrix;
}
7. 피보나치 공식
- 이와 같이?
/**
* Math - Fibonacci Formula
* Time O(log(N)) | Space O(1)
* https://leetcode.com/problems/climbing-stairs/
* @param {number} n
* @return {number}
*/
var climbStairs = (n, sqrt5 = Math.sqrt(5)) => {
const phi = ((sqrt5 + 1) / 2);
const psi = ((sqrt5 - 1) / 2);
const phiPow = Math.pow(phi, (n + 1));
const psiPow = Math.pow(psi, (n + 1));
return ((phiPow - psiPow) / sqrt5);
}
다음 중 귀하의 솔루션은 무엇입니까?