1793. 好子数组的最大分数(LeetCode),贪心双指针

解释看代码注解咯

给你一个整数数组 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 <= 105
  • 1 <= nums[i] <= 2 * 104
  • 0 <= k < nums.length

 

//
// Created by py on 24-3-19.
//
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <deque>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>

using namespace std;

class Solution {
public:
    /*
     * 暴力递归
     * 跳过
     * */
    vector<int> arr;
    int sizeArr;
    int p;
    priority_queue<int, vector<int>> priorityQueue;

    void process(int left, int right, int minNum) {
        if (left < 0) return;
        if (left > right) return;
        if (right == sizeArr) return;
        priorityQueue.push(minNum * (right - left + 1));
        if (left != 0) {
            process(left - 1, right, minNum < arr[left - 1] ? minNum : arr[left - 1]);
        }
        if (right != sizeArr - 1) {
            process(left, right + 1, minNum < arr[right + 1] ? minNum : arr[right + 1]);
        }

    }
    /*
     * 暴力循环
     * 跳过
     * */
    int violentDpProcess(vector<int> nums, int k) {
        int ans = INT32_MIN;
        int startMinNum = 2 * 10e4 + 7;
        for (int i = k; i < nums.size(); ++i) {
            int minNum = startMinNum > nums[i] ? nums[i] : startMinNum;
            startMinNum = minNum;
            for (int j = k; j >= 0; --j) {
                minNum = min(minNum, nums[j]);
                ans = max(minNum * (i - j + 1), ans);
            }
        }
        return ans;
    }
    /*
     * 核心思想:双指针滑动区域,求得每一个区域的分数最大值,利用贪心算法,滑动指针
     * 请看代码
     * */
    int doublePointProcess(vector<int> nums, int k) {
        int n = nums.size(); // 搞个变量存数组的值
        int left = k; // 左右指针
        int right = k;

        int minNum = nums[k];//这个区域的最小值变量,第一次是从 k 开始的 ,因为这个区域必定包含下标为 k 的值
        int ans = -1;//答案变量
        // true 是不知道怎么搞当时,就循环内结束了
        while (true) {
            /*
             * 这里我是习惯一开始就计算一次答案值
             * */
            ans = max((right - left + 1) * minNum, ans);
            // 循环结束标识
            if (left == 0 && right == n - 1) {
                break;
            }
            // left 到边界了,但是我们不确定继续往右走是否会比答案还要大,因为是 乘法 一个减小一个变大 难说哪个大
            if (left == 0) {
                right++;
                // 更新区域最小值
                minNum = min(minNum,nums[right]);
            }
            // 同理left == 0
            else if (right == n - 1) {
                left--;
                // 更新区域最小值
                minNum = min(minNum,nums[left]);
            }
            // 利用贪心算法,我们专门去取尽可能大的数
            /*
             * 这里可以证明一下:1,4,3,7,4,5 ; k = 1
             * 假如现在left = 1,right = 1
             * 很明显假如这次区域往右走,区域值比往左走大 左边:(1,4)= 2  ;;右边:(4,3) = 6
             * 以后也是同理
             * */
            else if (nums[left - 1] > nums[right + 1]) {
                left--;
                minNum = min(minNum,nums[left]);
            } else {
                right++;
                minNum = min(minNum,nums[right]);
            }
        }
        return ans;
    }

    int maximumScore(vector<int> nums, int k) {
        return doublePointProcess(nums, k);
        /*
         * 想玩暴力的可以看看
         * */
        return violentDpProcess(nums,k);
        arr = nums;
        p = k;
        sizeArr = nums.size();
        process(k, k, nums[k]);
        return priorityQueue.top();
    }
};

int main() {
    Solution solution;
    cout << solution.maximumScore(
            {1339, 6671, 9827, 4155, 5138, 3088, 86, 3742, 462, 5139, 1983, 112, 8362, 8298, 9858, 411, 1986, 633, 593,
             1664, 403, 4775, 9969, 8508, 2288, 3163, 5907, 4817, 5789, 7599, 1750, 5842, 6051, 7737, 1641, 6176, 736,
             487, 2078, 3195, 3074, 4649, 5352, 4262, 771, 5541, 3291, 905, 7502, 3128, 4001, 3849, 1518, 4577, 1505,
             2104, 6123, 6052, 3796, 2869, 4530, 3752, 8086, 3221, 2136, 8112, 3055, 645, 941, 5053, 8895, 3363, 5241,
             9581, 8109, 4728, 6376, 8655, 9778, 8774, 9827, 2489, 7656, 2204, 858, 3755, 7108, 2451, 7350, 9020, 9777,
             8593, 7856, 1721, 1507, 1856, 8200, 7446, 9211, 5049, 4554, 6934, 6940, 6660, 1189, 9538, 1547, 5744, 6621,
             6852, 6910, 5425, 2976, 4325, 1080, 4575, 7550, 6960, 3943, 8344, 4164, 2606, 8544, 2512, 633, 6797, 2909,
             9089, 6036, 1641, 5410, 5865, 7845, 2080, 1470, 6976, 5972, 7485, 4391, 3387, 9871, 5950, 4080, 9122, 5233,
             4752, 6394, 1311, 1922, 908, 7340, 1012, 1856, 2879, 7480, 8188, 1077, 2748, 8367, 1219, 5051, 1077, 2433,
             9044, 7171, 6221, 1637, 4559, 3842, 7776, 4102, 352, 780, 8010, 4444, 8497, 4531, 1730, 3796, 3365, 1133,
             1065, 3208, 5833, 9135, 7029, 4892, 8922, 2344, 1389, 983, 3091, 1509, 2925, 4795, 1776, 2956, 7767, 9311,
             9311, 897, 6195, 2563, 9874, 3318, 4005, 4179, 4561, 5257, 6768, 7584, 4962, 4428, 841, 6683, 3657, 4742,
             483, 8287, 9636, 4625, 5354, 1469, 683, 3423, 9621, 1138, 2600, 6, 933, 7545, 5753, 5541, 2589, 4754, 8248,
             7392, 8827, 9750, 9457, 4129, 4527, 9825, 5993, 266, 3257, 9438, 9293, 955, 9182, 6583, 1785, 7492, 2192,
             1167, 2398, 2568, 2260, 6639, 2289, 1143, 742, 8083, 5567, 57, 1640, 2486, 6070, 6854, 8619, 4147, 2188,
             2969, 6969, 7710, 2407, 6617, 2631, 1977, 2984, 1051, 9044, 8088, 5646, 8940, 9643, 9298, 6193, 9799, 9083,
             7639, 9123, 5261, 6692, 650, 4410, 9158, 242, 4468, 2686, 3117, 365, 2335, 2911, 4896, 8764, 8668, 7682,
             948, 121, 7638, 1265, 7065, 6076, 2002, 5713, 9644, 6710, 7931, 7941, 6316, 6789, 7459, 6360, 8354, 4090,
             2090, 955, 7240, 7441, 6605, 6307, 7419, 1352, 2021, 9526, 1361, 9793, 2922, 5115, 2714, 3032, 9769, 9902,
             6489, 1358, 848, 6371, 2772, 9735, 352, 4905, 6349, 4556, 2722, 3231, 3610, 2142, 6818, 1123, 6053, 87,
             625, 1143, 5188, 6749, 3324, 2049, 4498, 1440, 4345, 7608, 1661, 8448, 6398, 2805, 7022, 7440, 5196, 2739,
             6302, 1515, 3004, 6917, 4344, 5278, 9726, 6595, 6856, 3723, 9639, 6232, 9926, 7887, 8172, 1112, 9938, 5614,
             8480, 7042, 7279, 1882, 1079, 2768, 9831, 3853, 6121, 169, 6833, 8763, 7112, 8526, 6866, 3601, 7581, 2275,
             1668, 2778, 3310, 9168, 1448, 9264, 1371, 644, 6003, 1134, 7397, 7203, 9164, 807, 226, 4353, 1974, 1682,
             1750, 1437, 3032, 7964, 46, 1065, 8740, 9515, 9349, 1837, 1025, 5400, 6885, 9475, 3392, 615, 9241, 4005,
             9006, 5468, 8618}, 232);
    return 0;
}

 

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值