日常刷题0x1之德玛蹲草丛

96 阅读1分钟

此阶段给自己定的目标是:做过的这些题每天坚持继续刷二遍,每道题做过之后开始尝试多解法尝试解题。上一阶段是感知都有什么题目,此阶段主要系统化常规题解套路知识,牢记牢记此阶段目的。

题号: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
};