最近在牛客网听左神讲课,在此记录一下。
题目是leetcode 354. Russian Doll Envelopes
问题:给定一个N*2的二维数组,看作是一个个二元组,例如[[a1,b1],[a2,b2],[a3,b3]], 规定:一个如果想把二元组甲放在二元组乙上,甲中的a值必须大于乙中的a值,甲中的b 值必须大于乙中的b值。如果在二维数组中随意选择二元组,请问二元组最多可以往上摞几个?
例如:[[5,4],[6,4],[6,7],[2,3]], 最大数量可以摞3个,[2,3] => [5,4] => [6,7] 要求:实现时间复杂度O(N*logN)的解法。
解法:这道题的算法原型是最长递增子序列,如果我们确定a的排列,在对b求解他的最长递增子序列即可。求解过程:先按a从小到大进行排序,当a相同时,按b从大到小排序。然后求解b的最长递增子序列。为什么b要按从大到小排列呢?按照最长递增子序列的O(N*logN),当前数大于h数组中末尾的数,我们会添加在h数组中;否则在h中查找第一个大于当前数的数并替换之。所以我们的做法会保证a相等的情况下,b可以有一个最小值,这样可以摞相对多的数。以达到最多,同时避免了a相同b不相同时摞在一起的情况。
package dome;
import java.util.Arrays;
import java.util.Comparator;
public class LeetCode354 {
/** 二元组 */
public static class Dot {
int a, b;
public Dot(int a, int b) {
this.a = a;
this.b = b;
}
}
/*** 比较器 */
public static class DotComparator implements Comparator<Dot> {
@Override
public int compare(Dot o1, Dot o2) {
if (o1.a == o2.a) {
return o2.b - o1.b;// 这里按b从大到小排序
} else {
return o1.a - o2.a;
}
}
}
/** 开始查找 */
private int maxEnvelops(int[][] es) {
Dot[] dots = new Dot[es.length];
for (int i = 0; i < es.length; i++) {
dots[i] = new Dot(es[i][0], es[i][1]);
}
Arrays.sort(dots, new DotComparator());
int[] h = new int[es.length];
h[0] = dots[0].b;
int hl = 0;// h中数据个数
int r = 0;
int l = 0;
int mid = 0;
for (int i = 1; i < dots.length; i++) {
r = hl;
l = 0;
while (l <= r) {
mid = (l + r) / 2;
if (h[mid] < dots[i].b) {
l = mid + 1;
} else {
r = mid - 1;
}
}
hl = Math.max(hl, l);
h[l] = dots[i].b;
}
return hl + 1;
}
// public static void main(String[] args) {
// int es[][] = { { 4, 5 }, { 4, 6 }, { 6, 7 }, { 2, 3 }, { 1, 1 } };
// System.out.println(maxEnvelops(es));
// }
}