找到数组

时间:2017-05-21 20:26:59

标签: c++ arrays algorithm vector

给定一些整数数组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),即使假设使用二进制搜索等基本实现,也可以立即看到。

2 个答案:

答案 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))。