题目源自于待字闺中的微信,是Pinterest公司的一道面试题。
题目:给如下的数据格式:
<start_time, end_time, value>比如有一组数据:
1, 3, 100
2, 4, 200
5, 6, 300
……
这些数据时间区间可能有重合的部分。比如在时间段2~3之间,value的和是100+200 = 300.。
要求找出这组数据中最高的value和。
思路:
不好的做法:看到题目中的时间都是整数值,即把时间看做离散值,一个思路是做一个把所有时间点建成一个数组,然后给所有时间点做计数统计。所需要的空间复杂度是O(k),并且k和输入数据中的时间范围有关,并且还需要计算时间范围。所需要的时间复杂度是O(n*n),因为对每一条数据都要循环做一次计数。并且,如果输入数据中的时间有小数(或者说时间值不是离散的),那么这个做法就失效了。
改进思路:上一个思路因为不能处理连续的时间值数据。想到使用链表来记录时间段的value总值,链表按时间排序,并且链表每个结点的时间区间不重叠。每当录入一条输入数据,检查这条数据的时间区间。如果是全新的时间区间,就新建一个新的结点插入到对应的位置;如果需要切割原链表时间区间,则修改原链表中对应的结点的区间,并新建一个结点插入到对应位置;如果这条数据的时间区间已经全部在链表中覆盖有,则将相应结点的value值更新一下。这个过程,过于复杂了!
优化思路:上一个思路太复杂了,换一个思路,海阔天空。过程化的思想,栈的思想。将一个时间区间A看作一组动作,进入A看做入栈,离开A看做出栈。那么在整个时间轴上从左到右,伴随着若干个出入栈动作,入栈动作对应value的增加,出栈动作对应value的减小。栈中的总值就是当前时间处的value总值,其不断更新。题目要寻找的,就是在value总值在更新过程中的最大值。
优化思路的解法:
1、先将输入数据拆分为入、出两个动作,记作(time, val)。入的时间就是start_time,入的动作是加上value值;出的时间就是end_time,出的动作是加上-value值。需要O(n)时间。
2、将所有的出入动作依据时间做一个排序,需要O(logn)时间。
3、设定一个value总值和max:对有序的入出动作做线性扫描,并实时更新value值和max值。最终将得到所寻找的max值。
代码:时间复杂度为O(logn + n),空间复杂度为O(n)。
void find_max(vector<vector<int> > input)
{
int n = input.size();
int i;
vector<int> onedata;
vector<vector<int> > data;
for(i=0;i<n;i++)
{
onedata.clear();
onedata.push_back(input[i][0]);
onedata.push_back(input[i][2]);
data.push_back(onedata);
onedata.clear();
onedata.push_back(input[i][1]);
onedata.push_back(-input[i][2]);
data.push_back(onedata);
}
sort(data.begin(), data.end());
int sum = 0;
int max = data[0][1];
for(i=0;i<2*n;i++)
{
sum += data[i][1];
if(sum > max)
max = sum;
}
return max;
} //代码我是大致写的,并没有完整编译测试
一个好的思路,真的可以使得问题解决简化很多。

本文详细解析了一道来自Pinterest公司的面试题,题目要求在一组包含时间区间和值的数据集中找到最大值。通过逐步优化思路,从离散计数到链表管理再到栈操作,最终提出了一种时间复杂度为O(logn+n),空间复杂度为O(n)的高效解决方案。此方法简洁明了,解决了时间区间重叠的问题。
12万+

被折叠的 条评论
为什么被折叠?



