【牛课堂第二季】第一章 俄国沙皇问题

转载自 俄国沙皇问题

问题

     
     
1
2
3
4
5
     
     
给定一个 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)的解法

思路

在解决这道题目之前,首先搞清楚一个问题:最长递增子序列 ;最长递增子序列为本题的算法原型。

那么问题来了,最长递增子序列是对一元数列的求解。此问题是二元组。如何将二元转换到一元,将复杂问题转换到我们已知的算法原型上来,成为本题的破题点。这也是俄国沙皇问题最精彩的地方。

重要思想:控制变量
1.以a的值进行升序排列
2.当a有序后,由b的值组成一元序列,对该序列查找最长子序列

现在思考:当a相同时,b该如何排序;这是讲二元转换成一元问题的关键。我们采取的策略是,a值相同时,b降序排列,a按照从小到大排序,b按照从大到小排序。这样保证了,排在后面的二元组。只要b值比前面的二元组大,则一定可以摞上去。a值相同,若b值升序排列,b值大的不一定能摞上。因为只有保证a,b同时大于前面的二元组,才符合题意。

核心代码

     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
     
     
struct dot
{
int a;
int b;
}dots[length];
int cmp( const void *a , const void *b )
{
struct dot *c = (dot *)a;
struct dot *d = (dot *)b;
if(c->a != d->a)
return c->a - d->a;
else
return d->b - c->b;
}
int searchInsert(int A[], int n, int target)
{
int low = 0, high = n -1;
while(low < high)
{
int mid = low+((high-low)>> 1);
if(A[mid] >= target)
high = mid;
else
low = mid+ 1;
}
return low;
}
int LIS_len()
{
int index = 0;
int insert = 0;
//二元组排序,利用cmp规定排序策略
qsort(dots, length, sizeof(dots[ 0]),cmp);
for ( int i = 1; i < length; i++)
{
if (dots[i].b > h[index])
{
index++;
h[index] = dots[i].b;
}
else
{
insert = searchInsert(h, index + 1, dots[i].b);
h[insert] = dots[i].b;
printf( "%d,%d\n", insert, h[insert]);
}
}
return index + 1;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值