算法练习day27

78 阅读2分钟

一、贪心算法理论基础

贪心的本质是选择每一个阶段的局部最优,从而达到全局最优

贪心没有套路,就是常识性推到加上举反例

二、分发饼干

局部最优为大饼干给胃口大的或者小饼干给胃口小的,充分利用饼干,全局最优就是喂饱尽可能多的小孩

/**
 * @param {number[]} g
 * @param {number[]} s
 * @return {number}
 */
var findContentChildren = function(g, s) {
    let res = 0
    let i = 0
    let j = 0
    g.sort((a, b) => a - b)
    s.sort((a, b) => a - b)
    while(i < g.length && j <  s.length) {
        if(s[j] >= g[i]) {
            i++
            j++
            res++
        } else {
            j++
        }
    }
    return res
};

三、摆动序列

局部最优,删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度上就可以有两个局部峰值

/**
 * @param {number[]} nums
 * @return {number}
 */
var wiggleMaxLength = function(nums) {
    if(nums.length < 2) {
        return nums.length
    }
    let preDiff = 0
    let curDiff = 0
    let index = 1
    let res = 1
    while(index < nums.length) {
        curDiff = nums[index] - nums[index - 1]
        if((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {
            res++
            preDiff = curDiff
        }
        index++
    }
    return res
};

动态规划思路

对于位于i位置的数,可能为波峰或者波谷,

dp[i][0]表示前i个数,第i个数作为波峰的摆动子序列的最长长度 dp[i][1]表示前i个数,第i个数作为波谷的摆动子序列的最长长度

状态转移方程

dp[i][0] = max(dp[i][0], dp[j][1] + 1) , 其中 0 < j < i 且 nums[j] < nums[i] dp[i][1] = max(dp[i][1], dp[j][0] + 1) , 其中 0 < j < i 且 nums[j] > nums[i]

初始状态

dp[0][0] = dp[0][1] = 1

var wiggleMaxLength = function(nums) {
    let dp = new Array(nums.length).fill(0).map(_ => [0, 0])
    dp[0][0] = 1 // 波峰
    dp[0][1] = 1 // 波谷
    for(let i = 1;  i< nums.length;i++) {
        dp[i][0] = 1
        dp[i][1] = 1
        for(let j = 0;j < i; j++) {
            if(nums[j] > nums[i]){
                dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1)
            }
        }
        for(let j = 0;j < i; j++) {
            if(nums[j] < nums[i]){
                dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1)
            }
        }
    }
    return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1])
};

四、最大子序和

贪心思路

局部最优为 当前连续和为负数的时候立刻放弃,从下个元素重新计算连续和,因为负数会拉低总和

只要连续和为正,对后面的元素起到增大总和的作用

只要有更大的连续和出现,result就会更新

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    let result = -Infinity
    let sum = 0
    for(let i = 0; i < nums.length;i++) {
        sum += nums[i]
        if(sum > result) {
            result = sum
        }
        // 当和小于等于0的时候,对结果对总和是拖累的
        if(sum <= 0) {
            sum = 0
        }
    }
    return result
};