1423. 可获得的最大点数

165 阅读2分钟

1423. 可获得的最大点数

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。

每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。

你的点数就是你拿到手中的所有卡牌的点数之和。

给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。

示例 1:

输入:cardPoints = [1,2,3,4,5,6,1], k = 3 输出:12 解释:第一次行动,不管拿哪张牌,你的点数总是 1 。但是,先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12 。

具体题目链接: 题目链接

思路:

思路:滑动窗口思路

窗口扩展时寻找可行解,窗口收缩时优化可行解

当滑动窗口可以定长时,一直维护k个长度的滑动窗口即可

当滑动窗口需要不定长时,需要通过特定条件(比如滑动窗口的总和)来判断left和right指针 到底是移动哪个

分析:

可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。获得的最大点数 可以转化成 从中间拿n-k张卡牌,获得的最小点数 也就是说滑动窗口为n-k,统计最小值,

代码:

var maxScore = function(nums, k) {
    let n = nums.length;

    let window = 0;
    //获得第一个n-k窗口的总和
    for(let i=0;i<n-k;i++) {
        window += nums[i];
    }
    //循环获取剩下的n-k个窗口
    let res = window;
    // 滑动窗口的定长
    let windowsize = n-k;
    //滑动窗口最右边的值
    let right = windowsize;
    while(right<n) {
        //滑动窗口最左边的值
        let left = right - windowsize;
        // 维护当前窗口的总和
        window = window + nums[right] - nums[left];
        //求最小值
        res = Math.min(res, window);

        right++;
    }

    let ans = 0;//nums各个子数组的和
    for(let i=0;i<n;i++) {
        ans+=nums[i];
    }
    return ans - res;//返回总和减中间最小值,就是两边最大值
};

总结:

这是算法系列文章「二分专题」的相关题解