给定一个 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)的解法
C++实现代码
#include
#include
using namespace std;
class Dot
{
public:
int w;
int h;
};
int cmp(Dot &a, Dot &b){
if (a.w < b.w)//w的值从小到大排列
return 1;
else
if (a.w == b.w){
if (a.h > b.h)//h的值从大到小排列
return 1;
else
return 0;
}
else
return 0;
}
int maxEnvelopes(int (*es)[2],int length)
{
if (es ==NULL || length <= 0 || es[0] == NULL) {
return 0;
}
Dot* dots = new Dot [length];
for (int i = 0; i < length; i++)
{
dots[i].w = es[i][0];
dots[i].h = es[i][1];
}
sort(dots,dots+length,cmp);//此处为 w升序 h降序排列,辅助数组对h进行处理;若 h升序 w降序排列,则辅助数组应对w进行处理
int*ends = new int[length];
ends[0] = dots[0].h;
int right = 0;
int l = 0;
int r = 0;
int m = 0;
for (int i = 1; i < length; i++) {
l = 0;
r = right;
while (l <= r) {
m = (l + r) / 2;
if (dots[i].h > ends[m]) {
l = m + 1;
}
else {
r = m - 1;
}
}
right = right>l?right:l;
ends[l] = dots[i].h;
}
return right + 1;
}
//此处为函数原型主要是二分查找,外圈算法复杂度O(n),内圈为O(logn)故整个复杂度为O(nlogn)
int ER(int *a,int length)
{
if (a == NULL || length < 0)return 0;
int *end = new int[length];
int l, r = 0, m = 0;
int right = 0;
end[0] = a[0];
for (int i = 1; i < length; i++)
{
l = 0;
r = right;
while (l <= r)
{
m = (r + l) / 2;
if (a[i]>end[m])
l = m + 1;
else
r = m - 1;
}
end[l] = a[i];
right = l > right ? l : right;
}
return right + 1;
}
int main()
{
//int a[] = {2,1,6,4,5,2,7,4};
//cout << ER(a, 8);
int test[7][2] = { { 4, 3 }, { 1, 2 }, { 5, 7 }, { 5, 3 }, { 1, 1 }, { 4, 9 }, {6,8} };
cout << maxEnvelopes(test,7);
return 0;
}
函数原型 ER()
可用于查找整数序列的最长递增子序列例如{2,-2,6,-1,5,2,7,4},调用ER()得到4。
过程:
同等长度辅助数组
(1)2
辅助数组 2
(2)-2 (-2比2小替换掉2)
辅助数组 -2
(3)6(6比-2大,扩大辅助数组)
辅助数组 -2 ,6
(4)-1(-1比6小,替换6)
辅助数组 -2,-1
(5)5 (5大于-1,扩大数组)
辅助数组 -2,-1, 5
(6)2 (2小于5)
辅助数组 -2,-1, 2
(7)7 (7大于2,扩大数组)
辅助数组 -2,-1 ,2, 7
(8)4 (4小于7,替换)
辅助数组 -2,-1, 2, 4
最后得到最长递增子序列的即为辅助数组的长度(设置以全局变量来记录辅助数组的长),
上述过程即为函数原型ER()的过程