给定一些整数数组A = [a 0 , 1 ,..., n ],找到最小距离在 i 和 j 之间,使得 i = a j 和i!= j(或表示没有这样的指数)。
所以我在C ++中实现了一种天真的O(n 2 )方法,包括迭代遍历数组寻找相等的元素并适当地更新最小距离:
#include <vector>
#include <climits>
#include <algorithm>
int MinPair(const std::vector<int>& nums)
{
int ret = std::numeric_limits<int>::max();
for(int i = 0; i != nums.size(); ++i)
{
for(int j = 0; j != i; ++j)
{
if(nums[i] == nums[j])
ret = std::min(ret, i - j);
}
}
if(ret == std::numeric_limits<int>::max())
return -1;
return ret;
}
这很有效,但我被告知更多有效的&#34;存在涉及std :: map的实现,没有更多关于什么更有效的说明。也就是说,可以遍历输入数组并在地图中存储元素的第一次出现,并且对于每次后续出现,找到该出现与地图中该元素的第一个索引之间的距离。如果该距离小于当前最小值,则我们更新该最小值。
然而,我没有看到这种方式更有效率。&#34;时间复杂度方面,你仍然需要遍历输入数组(O(n)),并使用std :: map :: find来识别元素是否是第一次出现也是O(n) ,总复杂度为O(n 2 )。在空间复杂性方面,除了数组/向量之外,还必须存储地图。我到底错过了什么?
编辑:我错误地认为map :: find是O(n);插入和查找操作实际上是O(log n),即使假设使用二进制搜索等基本实现,也可以立即看到。
答案 0 :(得分:3)
我最初发布了一个类似于grigor提到的解决方案的编码解决方案。然后我意识到有一个明显的优化,使整个事情在O(N)时间内工作,以获得最佳案例和平均案例。
typedef pair<bool, int> LastPositionFound;
int MinPair(const std::vector<int>& nums)
{
unordered_map<int, LastPositionFound> table; // maps value found in array to the last position that value was seen at.
int best_distance = -1;
for (size_t index = 0; index < nums.size(); index++)
{
int value = nums[index];
LastPositionFound& lpf = table[value]; // returns {false,0} if not found
if (lpf.first)
{
int distance = index - lpf.second;
if ((distance < best_distance) || (best_distance == -1))
{
best_distance = distance;
}
}
// update reference to hash table entry
lpf.first = true;
lpf.second = index;
}
return best_distance;
}
答案 1 :(得分:1)
您可以将每个元素映射到一组索引。所以你有map<int, set<int>> m
之类的东西,然后浏览你的向量:for(int i = 0, i < nums.size(); ++i) m[nums[i]].insert(i)
。之后,您可以遍历地图,如果元素有多个索引,则查找索引之间的最小距离。应该是O(nlog(n))。