【问题标题】:First Unique Number Slow runtime issue第一个唯一编号慢运行时问题
【发布时间】:2024-01-17 02:41:01
【问题描述】:

所以我最近在 Leetcode 上实现了“First unique number”。供参考的问题是这样的:

您有一个整数队列,您需要检索队列中的第一个唯一整数。

实现 FirstUnique 类:

  • FirstUnique(int[] nums) 用中的数字初始化对象 队列。
  • int showFirstUnique() 返回队列的第一个唯一整数的值,如果没有这个整数则返回-1。
  • void add(int value) 将值插入队列。

我使用 STL 的 C++ 实现使用 unordered_map 和列表。该映射将队列的元素存储为键,并存储指向列表中元素的迭代器和一个布尔值,指示当该值不再唯一时从列表中删除该值。向列表中添加和删除元素似乎是恒定时间操作。但是,与使用队列并遍历队列的另一个解决方案相比,我的解决方案要慢得多(与我的 O(1) 相比,它基本上看起来是 O(n))。

这是明显更糟糕的解决方案:

class FirstUnique {
        private:
        queue<int> q;
        unordered_map<int, int> count;
        public:
        FirstUnique(vector<int>& nums) {
            for(int num: nums){
                count[num]++;
                q.push(num);
            }
        }

        int showFirstUnique() {
            while(!q.empty() && count[q.front()] > 1){
                q.pop();
            }
            if(q.empty()){
                return -1;
            }
            else{
                return q.front();
            }
        }

        void add(int value) {
            if(++count[value] == 1){
                q.push(value);
            }
        }
    };

这是我的解决方案:

class FirstUnique {
    public:
    unordered_map<int, pair<list<int>::iterator, bool>> hashmap;
    list<int> l;
    FirstUnique(vector<int>& nums) {
    for(auto it=nums.begin(); it!=nums.end(); it++)
        add(*it);
    }

    int showFirstUnique() {
        if (l.empty())
            return -1;
        return l.back();
    }

    void add(int value) {
        unordered_map<int, pair<list<int>::iterator, bool>>::iterator it = hashmap.find(value);
        if(it == hashmap.end())
        {
            l.push_front(value);
            hashmap[value] = make_pair(l.begin(), false) ;
        }

        else
        {
            if((it->second).second == false)
            {
                l.erase((it->second).first);
                (it->second).second = true;
            }
        } 
    }
 };

我不明白的是,尽管我的解决方案很快,但运行时间却慢得多。在 Leetcode 上,有队列的运行时间为 328 毫秒,而我的运行时间为 532 毫秒。我可以理解我的解决方案内存很重,但不明白为什么它会变慢。

【问题讨论】:

  • hashmap.find() 在复杂性上是线性的(最坏情况)。此外,常数时间并不总是比 O(n) 快,它在大多数情况下取决于 n(迭代一个小数组可能比索引到包含相同数量元素的哈希图更快)。这意味着,如果在定时运行期间使用您的 add 方法,那么您的解决方案会慢一些也就不足为奇了。

标签: c++ list stl queue unordered-map


【解决方案1】:

我们只需要 Java 中的 LinkedHashMap。这将跟踪收到的物品的订单。在构造函数中,我们将只标记唯一的数字。 在 add 方法中要做同样的事情。 在 showFirstUnique 中,我们将遍历地图并返回标记为唯一的地图。请参阅下面的代码以获得更清晰的信息。

class FirstUnique {
Map<Integer, Integer> map;

public FirstUnique(int[] nums) {
    map = new LinkedHashMap<>();

    for (int num : nums) {
        if (map.containsKey(num)) {
            map.put(num, 0);
        } else {
            map.put(num, 1);
        }
    }
}

public int showFirstUnique() {
    for (Integer key : map.keySet()) {
        if (map.get(key) == 1) {
            return key;
        }
    }
    return -1;
}

public void add(int value) {
    if (map.containsKey(value)) {
        map.put(value, 0);
    } else {
        map.put(value, 1);
    }
}
}

【讨论】:

    【解决方案2】:

    我们只需要将唯一值推送到列表中。为了跟踪唯一值,创建一个跟踪唯一值的无序映射。

    public:
        list<int> li;
        unordered_map<int, bool> m;
        FirstUnique(vector<int>& nums) {
            for(auto i:nums){
    
    //         if i is not in map then we push i to the list an make m[i] = true i.e. unique
    //         else we make it false. i.e. it is not unique now. 
    
                if(m.find(i) == m.end()){
                    li.push_back(i);
                    m[i] = true;
                }else{
                    m[i] = false;
                }
            }
    
        }
    
        int showFirstUnique() {
            for(auto it:li){
                if(m[it] == true){
                    return it;
                }
            }
            return -1;
    
        }
    
        void add(int value) {
            if(m.find(value) == m.end()){
                li.push_back(value);
                m[value] = true;
            }else{
                m[value] = false; 
            }
    
        }
    };
    

    【讨论】:

      最近更新 更多