满足不等式的最大值

目录

题目描述

分析


题目描述

分析

 按照题目含义,points数组已经按照x轴坐标进行升序排序

也就是说,若有0 <= i < j < points.size(),则必有points[i][0] < points[j][0](xi < xj);

所以我们可以将原表达式改写成   yi - xi + yj + xj;

面对这个表达式我的第一个想法就是开两个数组,diff数组负责记录yi - xi, sum数组负责记录yi + xi,其中0 <= i < points.size();

接着我们来思考如何来获取最大值

最简单的思考是枚举

因为,题目限制条件仅仅是对x轴做出限制,所以我们简化示意图,只考量x轴。

图1:问题简化图,每一个“框”(区间)的长度为k 


根据问题简化示意图,如果要枚举,那么我们要枚举各个区间的左端点,再者确定区间范围。最后在区间中逐个计算。每一层的复杂度大致在O(n),所以最后的枚举算法复杂度在O(n^2)。

代码如下:

class Solution {
public:
    int findMaxValueOfEquation(vector<vector<int>>& points, int k) {
        int n = points.size();
        
        int ans = INT_MIN;//赋值为最小int,0x80000000;
        for (int i = 0; i < n - 1; ++i) {
            int j;
            for (j = i + 1; points[j][0] - points[i][0] <= k; ++j) {};//确定范围

            for (int k = i + 1; k < j; ++k) {//逐个计算
                if (ans < points[i][1] - points[i][0] + points[k][1] + points[k][0]) {
                    ans = points[i][1] - points[i][0] + points[k][1] + points[k][0];
                }
            }
        }

        return ans;
    }
};

很可惜,枚举并不能通过此道题目。因为数据规模在10^5,而我们能够处理的数据规模在10^4

所以我们应该思考,如何优化算法

重新看回我们的简化示意图。

图2: 问题简化示意图


我们可以观察到,红色框区间与橙色框区间存在一定的重合,即交集为非空集合。当然两个区间(框)之间可能不存在重合,即交集为空集

换句话,当交集非空时,枚举算法存在重复区间的情况。所以我们可以对此进行优化。这里,我们可以使用双指针优化,用两个首尾指针的交替递进性枚举区间

当然,这个时候出现了一个问题!在枚举算法中,我们是枚举出区间后,遍历这个区间来达到计算区间的值。如果计算值算法不做优化,复杂度仍然处在O(n^2)。那么这仍然不能通过所有样例。

题目要求,我们只需要计算出“满足不等式的最大值”。那么在区间重合部分,两个区间是共有的。当我们计算后一个区间的最大值的时候,必然有前面一个最值已经获取。

为了方便表述:

记Si为以i为左端点且其中任意元素差的绝对值小于等于k,也就是示意图中的框,框的编号从0开始(i从0开始)。

如果我们获取到了Si中的最大值,那么我们S(i + 1)中满足不等式的最大值,一定有:

max{Si} = diff[pi] + sum[j];

max{S(i + 1)} = diff[p(i + 1)] + sum[j];

diff数组负责记录yi - xi, sum数组负责记录yi + xi

其中0 <= pi < p(i + 1) < j < points.size(),且j∈Si∩S(i + 1);

记ans(i)是S0到Si中满足不等式的最大值。那么当从Si过渡到S(i + 1)时,一定有以下语句成立吗?

if(diff[p2] > diff[p1]) ans += diff[p2] - diff[p1];

这显然是不正确的。有两个bug!根据式子转移的前提条件,我们列出两个bug:

记ans = diff[pk ∈ Sk] + sum[j ∈ Sk] 

1.Sk∩S(i + 1) = 空集合。

2.Sk∩S(i + 1) != 空集合,但是pk < j, p(i + 1) == j。

这两个bug的问题是不满足转移方程的条件。那么我们可以不处理bug吗?bug对我们答案会有影响吗?我用数学方式证明/判断一下。

假如我们有ans1和ans2。我们规定ans1就是当前的答案,即ans1 > ans2

但是ans1的取值条件不符合方程条件,而ans2符合。

那么ans2 + diff[pi] - diff[pk] 一定小于 ans1吗

显然这个问题我们是无法确定的,也就是存在反例的。至此我们可以使用反例来证明bug对我们的程序是有影响的。

通过上面的数学证明/判断,也告诉我们最终的最大值未必是当前最大值转换而来的!所以我们如果要消除bug,还需要记录产生的所有答案。为了加快程序,我么当然是优先处理最大值!也就是说只有当前最大不符合条件,才会去寻找其他值,并且首先寻找第二大值

正因为如此,我们可以想到用堆来维护产生的临时答案

代码如下:

class Solution {
public:
    using pii = pair<int, int>;
    int findMaxValueOfEquation(vector<vector<int>>& points, int k) {
        int res = INT_MIN;//初始化
        //为了维护两个属性
        //1.先取出最大的差值
        //2.左端点的x值先去出小值
        //将差值取反,使用小根堆
        priority_queue<pii, vector<pii>, greater<pii>> heap;
        for (auto &point : points) {
            int x = point[0], y = point[1];
            while (!heap.empty() && x - heap.top().second > k) {//不符合不等式要求,剔除
                heap.pop();
            }
            if (!heap.empty()) {//符合要求,更新答案
                res = max(res, x + y - heap.top().first);
            }
            heap.emplace(x - y, x);//压入新差值。
        }
        return res;
    }
};

当然也可以用大根堆维护,代码如下:

class Solution {
public:
    using pii = pair<int, int>;
    int findMaxValueOfEquation(vector<vector<int>>& points, int k) {
        int res = INT_MIN;
        priority_queue<pii> heap;
        for (auto &point : points) {
            int x = point[0], y = point[1];
            while (!heap.empty() && x + heap.top().second > k) {
                heap.pop();
            }
            if (!heap.empty()) {
                res = max(res, x + y + heap.top().first);
            }
            heap.emplace(y - x, -x);
        }
        return res;
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值