问题:
给定[1,k]范围内的n个整数,预处理其输入然后 回答有关n个整数中有多少个在a和b之间具有值的任何查询,其中1≤a,b≤k 是两个给定的参数。您的算法应使用O(n + k)预处理时间。
答案 0 :(得分:2)
您的算法相当不错,但可以更快地完成。具体来说,您的算法具有O(1)预处理时间,但由于执行分区步骤所需的线性成本,每个查询花费O(n)时间。
让我们考虑另一种方法。假设您的所有值都按排序顺序排列。在这种情况下,您可以通过仅执行两次二进制搜索来快速找到范围内的元素数量 - 第一次二进制搜索以查找下限的索引,第二次搜索以查找上限 - 并且可以仅减去指数。这需要时间O(log n)。如果您可以预处理输入数组以在时间O(n + k)中对其进行排序,那么这种方法将导致查找时间呈指数级增长。
要进行此排序,正如@minitech指出的那样,您可以使用计数排序算法,该算法在时间O(n + k)中对1到k之间的整数进行排序。因此,同时使用计数排序和二进制搜索可以得到O(n + k)设置时间和O(log n)查询时间。
但是,如果你愿意换取记忆效率,你可以进一步提高速度。我们假设k是一个相当小的数字(比方说,不超过100)。然后,如果你可以使用O(k)空间,你可以在O(1)时间内回答这些查询。这个想法如下:建立一个k元素表,表示对于每个元素k,原始数组的元素数小于k。如果你有这个数组,你可以通过查找有多少元素小于b以及有多少元素小于a(每个在O(1)时间内),然后减去它们来找到某个子范围中元素的总数。 / p>
当然,要做到这一点,你必须在时间O(n + k)中实际建立这个表。这可以如下完成。首先,创建一个k元素的数组,然后遍历原始的n元素数组,并为每个元素增加表中与该数字对应的点。当你完成时(在时间O(n + k)),你将在这个表中填写原始数组中存在1 - k范围内的每个值的次数(顺便提一下,计数排序的工作方式)。接下来,创建一个包含累积频率的k个元素的第二个表。然后,迭代您在第一步中构建的直方图,并使用累积的频率表填充在您走过直方图时遇到的累积元素总数。最后一步需要时间O(k),用于设置的总时间O(n + k)。您现在可以在时间O(1)中回答查询。
希望这有帮助!
答案 1 :(得分:0)
这是另一个简单的算法: 首先分配一个大小为k的数组A,然后迭代n个元素,对于每个整数x,将A [x]递增1。这将花费O(n)时间。 然后计算数组A的prefix sum,并将它们存储为数组B.这将采用O(k)。
现在对于点(a,b)的任何查询,您只需返回:B [b] -B [a] + A [a]