某道笔试题如下:
给出几组数据,如(20,30),(24,25),(30,40),(32,41),(x,y)中,x 代表身高,y代表体重。叠罗汉,下面的人要比上面的人身高低、体重小。问最多叠几层?
分析:此题目需要先按照”身高“数据排序(升序),然后求得排序后”体重“数据的最长递增子序列长度。
排序,可以采取二分法或者堆排序,时间复杂度不超过O(nlg(n))。 然后求”最长递增子序列长度“的高效代码如下(此题目也是《编程之美》2.16的一道题目):
时间复杂度:O(n) + o(nlog(n)),故时间复杂度是o(nlog(n))。
代码思路:可申请一个额外数组(空间换时间),其数组元素L[i],存放长度为i的递增序列,其最后元素的最小值。
一开始,L[1] = 1,然后被更新为-1, 然后被更新为-3,-5,-7。注意理解最后元素的最小值。
之所以L[i]存放“长度为i的序列最后元素的最小值”,是一种“贪心”策略,这样方便下次遍历一个新元素时,如大于新数组的当前元素,则可以直接扩展到最长序列的后面。
int BinSearch(int * MaxV, int size, int x)
{
int left = 0, right = size-1;
while(left <= right)
{
int mid = (left + right) / 2;
if(MaxV[mid] <= x)
{
left = mid + 1;
}else
{
right = mid - 1;
}
}
return left;
}
int LIS(int * arr, int size)
{
int len;
int MaxV[size];
MaxV[0] = arr[0];
for(int i = 1; i < size; ++i)
{
if(arr[i] > MaxV[len-1])
{
MaxV[len++] = arr[i];
}
else
{
int pos = BinSearch(MaxV,len,arr[i]);
MaxV[pos] = arr[i];
}
}
return len;
}