问:
- 给定N个台阶,有一个机器人,站在S位置上,可以向上或者向下走,规定走到1的时候只能向上,走到N的时候只能向下。若这个机器人走K步,有几种走法可以走到指定位置E?
- 有一个正数数组,给一个目标target,用最少几个数累加和等于target?
解: 1.
// 暴力递归
function goToEnd1(N, start, end, K) {
// cur:当前所在位置,surplusStep:剩余步数
function getRes(cur, surplusStep) {
if (surplusStep === 0) {
return cur === end ? 1 : 0
}
if (cur === 1) {
return getRes(2, surplusStep - 1)
}
if (cur === N) {
return getRes(cur -1, surplusStep - 1)
}
return getRes(cur-1, surplusStep - 1) + getRes(cur+1, surplusStep-1)
}
return getRes(start, K)
}
// 记忆化递归
function goToEnd2(N, start, end, K) {
// 存储已经计算过的值
const hashMap = new Map()
function getRes(cur, surplusStep) {
if (hashMap.has(`${cur}-${surplusStep}`)) return hashMap.get(`${cur}-${surplusStep}`)
if (surplusStep === 0) {
hashMap.set(`${cur}-${surplusStep}`, cur === end ? 1 : 0)
} else if (cur === 1) {
hashMap.set(`${cur}-${surplusStep}`, getRes(2, surplusStep - 1))
} else if (cur === N) {
hashMap.set(`${cur}-${surplusStep}`, getRes(cur -1, surplusStep - 1))
} else {
hashMap.set(`${cur}-${surplusStep}`, getRes(cur-1, surplusStep - 1) + getRes(cur+1, surplusStep-1))
}
return hashMap.get(`${cur}-${surplusStep}`)
}
return getRes(start, K)
}
// 暴力递归
function getMinNums(arr, target) {
// cur:当前遍历到的位置,sum:之前决策的总和
function getRes(cur, sum) {
// 已经超出,决策失败
if (sum > target) {
return -1
}
// 已经成功不需要在选了
if (sum === target) {
return 0
}
// 继续选
// 如果已经没有硬币可以选,决策失败
if (cur === arr.length) {
return -1
}
// 以 是否要当前值做决策
const p1 = getRes(cur + 1, sum)
const p2 = getRes(cur+1,sum + arr[cur])
// 如果后续决策有失败的,那么返回另一个决策,或者失败
if (p1 === -1 && p2 === -1) {
return -1
}
if (p1 === -1) {
return 1 + p2
}
if (p2 === -1) {
return p1
}
// 后续决策都有返回值,那么取更小的
return Math.min(p1, p2 + 1)
}
return getRes(0,0)
}
// 记忆化递归
function getMinNums2(arr, target) {
const hashMap = new Map()
function getRes(cur, sum) {
if (hashMap.has(`${cur}-${sum}`)) return hashMap.get(`${cur}-${sum}`)
// 已经超出,决策失败
if (sum > target) {
hashMap.set(`${cur}-${sum}`, -1)
}else if (sum === target) {
// 表示已经成功不需要在选了
hashMap.set(`${cur}-${sum}`, 0)
} else if (cur === arr.length) {
hashMap.set(`${cur}-${sum}`, -1)
} else {
// 以是否要当前值做决策
const p1 = getRes(cur + 1, sum)
const p2 = getRes(cur+1,sum+arr[cur])
// 如果后续决策有失败的,那么返回另一个决策,或者失败
if (p1 === -1 && p2 === -1) {
hashMap.set(`${cur}-${sum}`, -1)
}else if (p1 === -1) {
hashMap.set(`${cur}-${sum}`, 1 + p2)
}else if (p2 === -1) {
hashMap.set(`${cur}-${sum}`, p1)
} else {
// 后续决策都有返回值,那么取更小的
hashMap.set(`${cur}-${sum}`, Math.min(p1, p2 + 1))
}
}
return hashMap.get(`${cur}-${sum}`)
}
return getRes(0,0)
}
// 递归改dp
function getMinNums(arr, target) {
const N = arr.length - 1
const dp = []
// 生成二维表
for (let i = 0;i<=N;i++) {
dp.push([])
}
for (let i = 0; i <= target; i++) {
// 把最后一行的所有列都标为-1
dp[N][i] = -1
}
for (let i = 0; i <= N; i++) {
// 把每一行的target列标为0
dp[i][target] = 0
}
//
for (let cur = N-1; cur >= 0; cur--) {
for (let sum = target - 1; sum >= 0;sum--) {
const p1 = dp[cur+1][sum]
// sum+arr[cur]可能越界,即递归函数中sum>target的情况,返回-1
const p2 = dp[cur+1][sum+arr[cur]] ?? -1
if (p1 === -1 && p2 === -1) {
dp[cur][sum] = -1
} else if (p1 === -1) {
dp[cur][sum] = 1 + p2
} else if (p2 === -1) {
dp[cur][sum] = p1
} else {
dp[cur][sum] = Math.min(p1, p2 + 1)
}
}
}
return dp[0][0]
}