【教3妹学编程-算法题】最大和查询

文章讨论了一个编程问题,如何通过构建线段树数据结构来高效地处理给定整数数组nums1和nums2的查询,找到满足特定条件时nums1[j]+nums2[j]的最大值。作者介绍了使用二分法确定范围并利用线段树维护区间最大值的方法。
摘要由CSDN通过智能技术生成

还是单身狗

3妹:2哥,你有没有看到新闻“18岁父亲为4岁儿子落户现身亲子鉴定”
2哥 : 啥?18岁就当爹啦?
3妹:确切的说是14岁好吧。
2哥 : 哎,想我30了, 还是个单身狗。
3妹:别急啊, 2嫂肯定在某个地方等着你去娶她呢。又不是结婚越早越好。
2哥:是啊, 这孩子14岁当爹,也太早了。
3妹:2哥,你找女朋友有什么条件没有哇?
2哥 : emmm, 以前希望找一个温柔漂亮的, 现在嘛, 女的、活的。毕竟年龄已经很大了, 已经30了…
3妹:才30而已嘛, 女生很多都喜欢找个比自己大一点的~
2哥 : 哎,你们女生最大能接受比自己大多少岁啊?
3妹:emmm, 这么不好说,要看具体女生,一般大个3-5岁都可以吧。 2哥说到最大, 我今天看到一个最大和查询的题目,让我也来考考你吧~

考考你

题目:

给你两个长度为 n 、下标从 0 开始的整数数组 nums1 和 nums2 ,另给你一个下标从 1 开始的二维数组 queries ,其中 queries[i] = [xi, yi] 。

对于第 i 个查询,在所有满足 nums1[j] >= xi 且 nums2[j] >= yi 的下标 j (0 <= j < n) 中,找出 nums1[j] + nums2[j] 的 最大值 ,如果不存在满足条件的 j 则返回 -1 。

返回数组 answer ,其中 answer[i] 是第 i 个查询的答案。

示例 1:

输入:nums1 = [4,3,1,2], nums2 = [2,4,9,5], queries = [[4,1],[1,3],[2,5]]
输出:[6,10,7]
解释:
对于第 1 个查询:xi = 4 且 yi = 1 ,可以选择下标 j = 0 ,此时 nums1[j] >= 4 且 nums2[j] >= 1 。nums1[j] + nums2[j] 等于 6 ,可以证明 6 是可以获得的最大值。
对于第 2 个查询:xi = 1 且 yi = 3 ,可以选择下标 j = 2 ,此时 nums1[j] >= 1 且 nums2[j] >= 3 。nums1[j] + nums2[j] 等于 10 ,可以证明 10 是可以获得的最大值。
对于第 3 个查询:xi = 2 且 yi = 5 ,可以选择下标 j = 3 ,此时 nums1[j] >= 2 且 nums2[j] >= 5 。nums1[j] + nums2[j] 等于 7 ,可以证明 7 是可以获得的最大值。
因此,我们返回 [6,10,7] 。
示例 2:

输入:nums1 = [3,2,5], nums2 = [2,3,4], queries = [[4,4],[3,2],[1,1]]
输出:[9,9,9]
解释:对于这个示例,我们可以选择下标 j = 2 ,该下标可以满足每个查询的限制。
示例 3:

输入:nums1 = [2,1], nums2 = [2,3], queries = [[3,3]]
输出:[-1]
解释:示例中的查询 xi = 3 且 yi = 3 。对于每个下标 j ,都只满足 nums1[j] < xi 或者 nums2[j] < yi 。因此,不存在答案。

提示:

nums1.length == nums2.length
n == nums1.length
1 <= n <= 10^5
1 <= nums1[i], nums2[i] <= 10^9
1 <= queries.length <= 10^5
queries[i].length == 2
xi == queries[i][1]
yi == queries[i][2]
1 <= xi, yi <= 10^9

思路:

思考

先按nums1升序,然后一个个检查nums2,如果后面出现nums2比前面大,那说明前面那个数没有用了(两者都比你大,那么和也比你更大) 剔除掉无用数后,我们可以发现第一维是升序,第二维是降序。 对于每一个询问queries,我们可以用二分法找到第一个比x大的下标left(left之后的都比它大) 同理,可以找到比y大的下标right(right之前的都比它大) 接下来我们需要返回的答案就是left和right之间所有下标里和最大的值(线段树维护区间最大值)

java代码:

class Solution {
    public int[] maximumSumQueries(int[] nums1, int[] nums2, int[][] queries) {
        int n = nums1.length;
        int m = queries.length;
        Point[] ps = new Point[m + n];
        for (int i = 0; i < n; i++) {
            ps[i] = new Point(nums1[i], nums2[i], i, 0);
        }
        for (int i = 0; i < m; i++) {
            ps[i + n] = new Point(queries[i][0], queries[i][1], i, 1);
        }
        // p.q=0/1是为了让p.x相同时,nums的数排在前面,从而先update再query
        Arrays.sort(ps, (p1, p2) -> p1.x == p2.x ? (p1.q - p2.q) : (p2.x - p1.x));
        int end = (int)1e9;
        Node root = new Node(0, end, -1);
        int[] ans = new int[m];
        for (Point p : ps) {
            if (p.q == 0) {
                root.update(p.y, p.y, p.x + p.y);   // 单点更新
            } else {
                ans[p.idx] = root.query(p.y, end);  // 区间查询[p.y, end]
            }
        }

        return ans;
    }

    class Point {
        int x;
        int y;
        int idx;
        int q;

        public Point(int x, int y, int idx, int q) {
            this.x = x;
            this.y = y;
            this.idx = idx;
            this.q = q;
        }
    }

    class Node {
        int left;
        int right;
        int val;
        Node leftNode;
        Node rightNode;

        public Node(int l, int r, int v) {
            left = l;
            right = r;
            val = v;
        }

        public Node getLeftNode() {
            if (leftNode == null) {
                leftNode = new Node(left, left + (right - left) / 2, val);
            }
            return leftNode;
        }

        public Node getRightNode() {
            if (rightNode == null) {
                rightNode = new Node(left + (right - left) / 2 + 1, right, val);
            }
            return rightNode;
        }

        public void update(int lo, int hi, int v) {
            if (left > hi || right < lo) {
                return;
            }
            if (left >= lo && right <= hi) {
                val = Math.max(val, v);
                return;
            }
            getLeftNode().update(lo, hi, v);
            getRightNode().update(lo, hi, v);
            val = Math.max(val, leftNode.val);
            val = Math.max(val, rightNode.val);
        }

        public int query(int lo, int hi) {
            if (left > hi || right < lo || val == -1) {
                return -1;
            }
            if (left >= lo && right <= hi) {
                return val;
            }
            return Math.max(getLeftNode().query(lo, hi), getRightNode().query(lo, hi));
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值