此阶段给自己定的目标是:做过的这些题每天坚持继续刷二遍,每道题做过之后开始尝试多解法尝试解题。上一阶段是感知都有什么题目,此阶段主要系统化常规题解套路知识,牢记牢记此阶段目的。
题号:377
//递归下面没做优化会超时
var combinationSum4 = function (nums, target) {
let helper = (value) => {
if (value == 0) {
return 1
} else if (value < 0) {
return 0
}
let count = 0
for (let i = 0; i < nums.length; i++) {
const num = nums[i];
count += helper(value - num)
}
return count
}
let result = helper(target)
return result
};
//递归,备忘录剪枝优化一下
var combinationSum4 = function (nums, target) {
let record = new Map()
let helper = (value) => {
if (value == 0) {
return 1
} else if (value < 0) {
return 0
}
//如果有记录value的值就直接拿出来用
if (record.has(value)) {
return record.get(value)
}
let count = 0
for (let i = 0; i < nums.length; i++) {
const num = nums[i];
count += helper(value - num)
}
//如果没有记录value的值就在计算完毕之后保存
record.set(value, count)
return count
}
let result = helper(target)
return result
};
//动态规划
var combinationSum4 = function (nums, target) {
let table = new Array(target + 1).fill(0)
table[0] = 1
for (let i = 0; i <= target; i++) {
for (let j = 0; j < nums.length; j++) {
const num = nums[j];
//我的目标是找target为i的结果数
//如果i < num ,那么我选择此时此刻的num是无意义的
//因为一个num就超过了i那么就说明我选择了此时的num
//之后就找不到满足意义的组合
if (i >= num) {
table[i] += table[i - num]
}
}
}
return table.pop()
};
题号:96
//递归但是超时
var numTrees = function (n) {
let helper = (begin, end) => {
if (begin > end) {
return 1
}
let count = 0
for (let i = begin; i <= end; i++) {
let val1 = helper(begin, i - 1)
let val2 = helper(i + 1, end)
count += val1 * val2
}
return count
}
let result = helper(1, n)
return result
};
//记忆化递归优化
var numTrees = function (n) {
let map = new Map()//备忘录
let helper = (begin, end) => {
if (begin > end) {
return 1
}
if (map.has(`${begin}${end}`)) {
//备忘录中有直接用
return map.get(`${begin}${end}`)
}
let count = 0
for (let i = begin; i <= end; i++) {
let val1 = helper(begin, i - 1)
let val2 = helper(i + 1, end)
count += val1 * val2
}
//备忘录中没有记录
map.set(`${begin}${end}`, count)
return count
}
let result = helper(1, n)
return result
};
//动态规划
var numTrees = function (n) {
let table = new Array(n + 1).fill(0)
table[0] = 1
table[1] = 1
for (let i = 2; i <= n; i++) {
for (let j = 0; j <= i - 1; j++) {
// 左右子树符合题意的二叉搜索树的数量积
// table[i - 1 - j]右子树,这里要理解,区间4,5,6 和 1,2,3的
// 二叉搜索树的数量是一样的不在乎你是谁
table[i] += table[j] * table[i - 1 - j]
}
}
return table.pop()
};
题号:LCP 28. 采购方案
//暴力求解,超时
var purchasePlans = function (nums, target) {
let result = 0
for (let i = 0; i < nums.length; i++) {
let num1 = nums[i]
for (let j = i + 1; j < nums.length; j++) {
let num2 = nums[j]
if (num1 + num2 <= target) {
result++
}
}
}
return result
};
var purchasePlans = function (nums, target) {
//升序排序
nums.sort((a, b) => {
return a - b
})
//找两个值满足a+b<=target
let begin = 0, end = nums.length - 1, result = 0
while (begin < end) {
let num1 = nums[begin]
let num2 = nums[end]
if (num1 + num2 <= target) {
//此时在[begin,end]区间内固定begin减小end都满足题意
result += end - begin
begin++
} else {
end--
}
}
return result % 1000000007
};