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));
}
}
}