牛客网【2021】阿里巴巴编程题(4星)— 子集
一、原题描述
小强有n个物品,每个物品有两种属性
x
i
x^i
xi 和
y
i
y^i
yi 。他想要从中挑出尽可能多的物品满足以下条件:对于任意两个物品
i
i
i 和
j
j
j ,满足
x
i
<
x
j
x^i < x^j
xi<xj 并且
y
i
<
y
j
y^i<y^j
yi<yj 或者
x
i
>
x
j
x^i>x^j
xi>xj 并且
y
i
>
y
j
y^i > y^j
yi>yj 。问最多能挑出多少个物品。
要求:空间复杂度
O
(
n
)
O(n)
O(n),时间复杂度
O
(
n
l
o
g
(
n
)
)
O(nlog(n))
O(nlog(n))
二、相同类型题目 — 俄罗斯套娃信封问题
三、题解
3.1 思路
该类型题目是最长递增子序列问题。
- 使用 n ∗ 2 n * 2 n∗2 的数组存储 x i x^i xi 和 y i y^i yi 。
- 排序 — 按照 x i x^i xi 从小到大, y i y^i yi从大到小的规则排序。
- 使用 贪心 + 二分搜索 求得答案。
3.2 代码(Java)
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int t = Integer.parseInt(br.readLine());
for (int i = 0; i < t; i++) {
int n = Integer.parseInt(br.readLine());
int[][] xy = new int[n][2];
String[] xsStrArr = br.readLine().split(" ");
String[] ysStrArr = br.readLine().split(" ");
for (int j = 0; j < n; j++) {
xy[j][0] = Integer.parseInt(xsStrArr[j]);
xy[j][1] = Integer.parseInt(ysStrArr[j]);
}
Arrays.sort(xy, (a, b) -> (a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]));
List<Integer> g = new ArrayList<>();
g.add(xy[0][1]);
for (int j = 1; j < n; j++) {
int num = xy[j][1];
int sz = g.size();
if (num > g.get(sz - 1)) {
g.add(num);
} else {
int l = binarySearch(g, num);
g.set(l, num);
}
}
bw.write(g.size() + "\n");
}
bw.flush();
br.close();
bw.close();
}
public static int binarySearch(List<Integer> g, int target) {
int l = 0, r = g.size() - 1;
while (l <= r) {
int m = l + (r - l) / 2;
if (g.get(m) < target) {
l = m + 1;
} else {
r = m - 1;
}
}
return l;
}
}