leetcode 分发饼干 && 判断子序列 && 最长递增子序列 && 无重叠区间

149 阅读1分钟

455. 分发饼干

leetcode-cn.com/problems/as…

  • 贪心
    • 使用贪心策略,先将饼干数组和小孩数组排序。
    • 然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量。
/**
 * @param {number[]} g
 * @param {number[]} s
 * @return {number}
 */
var findContentChildren = function(g, s) {
    g.sort((a,b)=>b-a) // 胃口
    s.sort((a,b)=>b-a) // 饼干
    let gPointer = 0
    let sPointer = 0
    let res = 0
    while(sPointer < s.length && gPointer <g.length){
        if(s[sPointer] >= g[gPointer]){
            res ++ 
            sPointer ++ 
            gPointer ++
        }else{
            gPointer ++
        }
    }
    return res
};

392. 判断子序列

leetcode-cn.com/problems/is…

  • 贪心
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isSubsequence = function (s, t) {

    let sPointer = 0
    let tPointer = 0

    while (sPointer < s.length && tPointer < t.length) {
        if (s[sPointer] === t[tPointer]) {
            sPointer++
            tPointer++
        } else {
            tPointer++
        }
    }
    return sPointer === s.length 
};

300. 最长递增子序列

leetcode-cn.com/problems/lo…

  • 动态规划
    • 定义状态:由于一个子序列一定会以一个数结尾,于是将状态定义成:dp[i] 表示 以 nums[i] 结尾 的「上升子序列」的长度。注意:这个定义中 nums[i] 必须被选取,且必须是这个子序列的最后一个元素;
    • 考虑状态转移方程:
      • 遍历到 nums[i] 时,需要把下标 i 之前的所有的数都看一遍;
      • 只要 nums[i] 严格大于在它位置之前的某个数,那么 nums[i] 就可以接在这个数后面形成一个更长的上升子序列;
      • 因此,dp[i] 就等于下标 i 之前严格小于 nums[i] 的状态值的最大者 +1+1。
/**
 * @param {number[]} nums
 * @return {number}
 */
var lengthOfLIS = function(nums) {
    const dp = new Array(nums.length).fill(1)
    for(let i=1;i<nums.length;i++){
        let max = 1
        for(let j=0;j<i;j++){
            if(nums[i]>nums[j]){
                max = Math.max(max,dp[j]+1)
            }
        }
        dp[i] = max
    }
    return Math.max(...dp)

};

435. 无重叠区间

leetcode-cn.com/problems/no…

  • 动态规划 与最长递增子序列状态方程一样
/**
 * @param {number[][]} intervals
 * @return {number}
 */
var eraseOverlapIntervals = function (intervals) {
    if(intervals.length ===0 || intervals.length ===1){
        return 0
    }
    intervals.sort((a, b) => {
        if (a[0] === b[0]) {
            return a[1] - b[1]
        } else {
            return a[0] - b[0]
        }
    })
    const dp = new Array(intervals.length).fill(1)

    for(let i=1;i<intervals.length;i++){
        let max = 1
        for(let j=0;j<i;j++){
            if(intervals[i][0]>=intervals[j][1]){
                max = Math.max(max,dp[j]+1)
            }
        }
        dp[i] = max

    }
    return intervals.length - Math.max(...dp)

};
  • 贪心算法
    • 对于区间尾按从小到大排序 这么排序就能选取更多的区间(区间的长度越短越能放更多的区间)
    • 如果前一个选取的区间尾巴小于当前的区间头部(这是前一个区间的尾巴必然小于当前的区间尾巴因为已经拍好序了),说明是不重叠的,则区间的长度+1,并且把当前的区间赋值给前一个区间pre
/**
 * @param {number[][]} intervals
 * @return {number}
 */
var eraseOverlapIntervals = function (intervals) {
    if(intervals.length ===0 || intervals.length ===1){
        return 0
    }

    intervals.sort((a, b) => {
        if(a[1] ===b[1]){
            return a[0] - b[0]
        }else{
            return a[1] - b[1]
        }
    })
    let counter = 1
    let pre = 0
    for (let  right = 1; right < intervals.length;right ++) {
        if (intervals[right][0] >= intervals[pre][1]) { // 无重合
            counter++
            pre = right
        }
    }
    return intervals.length - counter
};