在careercup网站上,出现了这个问题(https://careercup.com/question?id=6270877443293184):
Given an array, find the number of tuples such that
A [i] + A [j] + A [k] = A [l] in an array, where i <j <k <l.
所提出的解决方案(下面)有效但状态运行时复杂度为O(n ^ 2)。在分析代码之后,我不认为它可以在少于n ^ 2 * log n的情况下完成。我的理由是它迭代遍历2d数组中的所有元素(n ^ 2并且它们在包含元组的列表中,检查每个元素,即O(n)。即使使用TreeMap并进行二进制搜索也可以只有减少是记录n,而不是常数时间。有人可以确认是否可以在O(n ^ 2)中完成并解释我的逻辑中有什么不正确吗?
建议的解决方案:
Fill 2 2d arrays with
arr1[i][j]=a[i]+a[j]
arr2[i][j]=a[j]-a[i]
j>i
In a map<int,list<int>>, map[arr1[i][j]].push_back(j)
For each element in arr2, search in the map.
Count all hits where j < k
答案 0 :(得分:0)
你是对的,在最坏的情况下,这不是O(n^2)
。
作者显然认为来自list
的{{1}}只包含少数成员;当我们声明哈希表的map<int,list<int>>
操作的复杂性是find
时,它就是我们使用的假设。回想一下,其冲突解析基于separate chaining的哈希表平均具有O(1)
操作的恒定复杂度,但是当许多元素散列到相同的值时,它可以降级为线性复杂度。 / p>
实现方面,请注意,映射find
需要是哈希表(即C ++中的map<int,list<int>>
,Java中的std::unordered_map
,而不是HashMap
(或{{ 1)}在Java中)因为只有std::map
TreeMap
操作std::map
find
。
答案 1 :(得分:0)
在j
中按升序排列map[arr1[][]]
非常容易。
如果以递增的k顺序枚举arr2中的每个元素,则不必进行二分查找。您可以枚举所有j
。
因为您要增加k
个订单,所以对于地图中的每个列表,您只需要记住您看到的最后一个列表。所以地图应该是map<int, <int, list<int>>>
。
由于您只触摸每个j
一次,而且复杂度仅为O(n^2)
。