LeetCode——1793. 好子数组的最大分数(Maximum Score of a Good Subarray)[困难]——分析及代码(Java)

LeetCode——1793. 好子数组的最大分数[Maximum Score of a Good Subarray][困难]——分析及代码[Java]

一、题目

给你一个整数数组 nums (下标从 0 开始)和一个整数 k 。
一个子数组 (i, j) 的 分数 定义为 min(nums[i], nums[i+1], …, nums[j]) * (j - i + 1) 。一个 好 子数组的两个端点下标需要满足 i <= k <= j 。
请你返回 好 子数组的最大可能 分数 。

示例 1:

输入:nums = [1,4,3,7,4,5], k = 3
输出:15
解释:最优子数组的左右端点下标是 (1, 5) ,分数为 min(4,3,7,4,5) * (5-1+1) = 3 * 5 = 15 。

示例 2:

输入:nums = [5,5,4,5,4,1,1,1], k = 0
输出:20
解释:最优子数组的左右端点下标是 (0, 4) ,分数为 min(5,5,4,5,4) * (4-0+1) = 4 * 5 = 20 。

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 2 * 10^4
  • 0 <= k < nums.length

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-score-of-a-good-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、分析及代码

1. 单调栈 + 双指针

(1)思路

根据题意,好子数组为从索引 k 向两侧延伸的数组,其分数取决于区间内的最小值和区间长度。
因此可在数组中索引为 k 的元素两侧,设计 2 个单调栈,存储各个最小值及对应的范围。在此基础上,结合双指针方法,遍历选取左、右区间中下一个较大的最小值(若相等则任意选取)并计算分数。过程中计算得到的分数最大值,就是待求的解。

(2)代码

class Solution {
    public int maximumScore(int[] nums, int k) {
        int n = nums.length, maxScore = 0;
        List<Integer> leftRange = new ArrayList<Integer>();//k左侧单调栈
        List<Integer> rightRange = new ArrayList<Integer>();//k右侧单调栈
        
        //向单调栈添加元素
        leftRange.add(k);
        rightRange.add(k);
        for (int i = k - 1; i >= 0; i--) {
            if (nums[i] < nums[leftRange.get(leftRange.size() - 1)])
                leftRange.add(i);
        }
        for (int i = k + 1; i < n; i++) {
            if (nums[i] < nums[rightRange.get(rightRange.size() - 1)])
                rightRange.add(i);
        }

        //在左、右单调栈上设计双指针,统计分数最大值
        int i = 0, j = 0, lenL = leftRange.size(), lenR = rightRange.size();
        while (i < leftRange.size() || j < rightRange.size()) {
            int l = (i == lenL - 1) ? -1 : leftRange.get(i + 1);//当前左侧最小值对应的左边界
            int r = (j == lenR - 1) ? n : rightRange.get(j + 1);//当前右侧最小值对应的右边界
            maxScore = Math.max(maxScore, Math.min(nums[leftRange.get(i)], nums[rightRange.get(j)]) * (r - l - 1));//计算score
            if (i == lenL - 1 && j == lenR - 1)//双指针均已到达边界
                break;
            else if (i == lenL - 1)//左单调栈已到达边界
                j++;
            else if (j == lenR - 1)//右单调栈已到达边界
                i++;
            else if (nums[l] <= nums[r])//选取左、右区间中下一个较大的最小值,若相等则任意选取
                j++;
            else
                i++;
        }
        return maxScore;
    }
}

(3)结果

执行用时 :11 ms,在所有 Java 提交中击败了 100.00% 的用户;
内存消耗 :48.2 MB,在所有 Java 提交中击败了 100.00% 的用户。
(目前提交用户量不足,暂无排名)

三、其他

暂无。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值