问:
解:
- 对于i位置的字符来说,前面[0,i-1]位置的字符都已经是固定的了,从[i,str.lengt-1]范围中每一个字符都有可能来到当前位置,交换它们在字符串中的位置,执行递归,并在递归结束后,把交换位置的数换回来。当 i 越界,结束递归并把字符串加入结果数组。
const permutation = function(str) {
const res = new Set()
str = Array.from(str)
function getRes(cur, curStr) {
if (cur === str.length) {
res.add(curStr.join(''))
return
}
for (let i = cur; i < str.length; i++) {
[curStr[cur], curStr[i]] = [curStr[i], curStr[cur]];
getRes(cur + 1, curStr);
[curStr[cur], curStr[i]] = [curStr[i], curStr[cur]]
}
}
getRes(0, str)
return [...res]
};
- 定义先手函数first,如果数组只有一个数,直接返回。先手可以分为两种情况,一种是拿了左边的数字,在加上这种情况下的后手分数。另一种是拿了右边的数字,在加上这种情况下后手的分数。定义后手函数,如果只有一个数,直接返回0.后手也可以分为两种,一种是被拿了左边数字之后
后手玩家成为了当前状况下的先手,另一种是被拿了右边数字之后后手玩家成为了当前状况下的先手。由于玩家选择最优解,所以先手玩家会返回两种情况的最优方案,后手玩家会返回最劣方案。
// 暴力递归
function smartPeople(arr) {
function first(arr, left, right) {
if (left === right) return arr[left]
const one = arr[left] + second(arr, left + 1, right)
const two = arr[right] + second(arr, left, right -1)
return Math.max(one, two)
}
function second(arr, left, right) {
if (left === right) return 0
const one = first(arr, left + 1, right)
const two = first(arr, left, right - 1)
return Math.min(one, two)
}
return Math.max(first(arr, 0, arr.length - 1), second(arr, 0, arr.length - 1))
}
// dp
const PredictTheWinner = function(nums) {
const dp1 = []
const dp2 = []
for (let i = 0; i < nums.length; i++) {
dp1[i] = []
dp2[i] = []
dp1[i][i] = nums[i]
dp2[i][i] = 0
}
for (let i = nums.length - 2; i >= 0; i--) {
for (let j = i + 1; j < nums.length; j++) {
dp1[i][j] = Math.max(dp2[i + 1][j] + nums[i], dp2[i][j - 1] + nums[j])
dp2[i][j] = Math.min(dp1[i + 1][j], dp1[i][j - 1])
}
}
return dp1[0][nums.length - 1] >= dp2[0][nums.length - 1]
};