更优雅的方法来检查C++数组中的重复项?

Sal*_*ara 16 c++ arrays duplicates

我在C++中编写此代码作为uni任务的一部分,我需要确保数组中没有重复项:

// Check for duplicate numbers in user inputted data
    int i; // Need to declare i here so that it can be accessed by the 'inner' loop that starts on line 21
    for(i = 0;i < 6; i++) { // Check each other number in the array
        for(int j = i; j < 6; j++) { // Check the rest of the numbers
            if(j != i) { // Makes sure don't check number against itself
                if(userNumbers[i] == userNumbers[j]) {
                    b = true;
                }
            }
            if(b == true) { // If there is a duplicate, change that particular number
                cout << "Please re-enter number " << i + 1 << ". Duplicate numbers are not allowed:" << endl;
                cin >> userNumbers[i];
            }
        } // Comparison loop
        b = false; // Reset the boolean after each number entered has been checked
    } // Main check loop
Run Code Online (Sandbox Code Playgroud)

它工作得很好,但我想知道是否有更优雅或有效的方法来检查.

Pup*_*ppy 19

您可以在O(nlog(n))中对数组进行排序,然后只需查看下一个数字即可.这比你的O(n ^ 2)现有算法要快得多.代码也更清洁.您的代码也不能确保在重新输入时不会插入重复项.您需要首先防止重复存在.

std::sort(userNumbers.begin(), userNumbers.end());
for(int i = 0; i < userNumbers.size() - 1; i++) {
    if (userNumbers[i] == userNumbers[i + 1]) {
        userNumbers.erase(userNumbers.begin() + i);
        i--;
    }
}
Run Code Online (Sandbox Code Playgroud)

我也推荐使用std :: set - 在那里没有重复.

  • 不,它是O(n*log(n)+ n) - 你排序然后搜索,而不是排序和搜索排序的每个操作. (5认同)
  • 当6接近无穷时,这当然更快;-) (2认同)

fre*_*low 9

以下解决方案基于对数字进行排序,然后删除重复项:

#include <algorithm>

int main()
{
    int userNumbers[6];

    // ...

    int* end = userNumbers + 6;
    std::sort(userNumbers, end);
    bool containsDuplicates = (std::unique(userNumbers, end) != end);
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,最好的答案是将`unique`替换为`adjacent_find`,因为它不会检查整个容器并将重复项移除,而是在找到第一个时返回. (6认同)

Pau*_*lik 7

事实上,最快和迄今为止我能看到的最优雅的方法如上所述:

std::vector<int> tUserNumbers;
// ...
std::set<int> tSet(tUserNumbers.begin(), tUserNumbers.end());
std::vector<int>(tSet.begin(), tSet.end()).swap(tUserNumbers);
Run Code Online (Sandbox Code Playgroud)

它是O(n log n).但是,如果需要保留输入数组中数字的顺序,则不会这样做...在这种情况下,我做了:

    std::set<int> tTmp;
    std::vector<int>::iterator tNewEnd = 
        std::remove_if(tUserNumbers.begin(), tUserNumbers.end(), 
        [&tTmp] (int pNumber) -> bool {
            return (!tTmp.insert(pNumber).second);
    });
    tUserNumbers.erase(tNewEnd, tUserNumbers.end());
Run Code Online (Sandbox Code Playgroud)

它仍然是O(n log n)并保持元素的原始排序tUserNumbers.

干杯,

保罗


Ben*_*ery 6

您可以添加集合中的所有元素,并在添加时检查它是否已存在.那将更加优雅和高效.


Jos*_*ers 5

我不确定为什么没有提出这个,但是这里有一种方法在10中找到O(n)中的重复项.我看到的已经建议的O(n)解决方案的问题是它需要数字首先排序..此方法是O(n),不需要对集进行排序.很酷的是检查特定数字是否有重复是O(1).我知道这个帖子可能已经死了,但也许它会帮助别人!:)

/*
============================
Foo
============================
* 
   Takes in a read only unsigned int. A table is created to store counters 
   for each digit. If any digit's counter is flipped higher than 1, function
   returns. For example, with 48778584:
    0   1   2   3   4   5   6   7   8   9
   [0] [0] [0] [0] [2] [1] [0] [2] [2] [0]

   When we iterate over this array, we find that 4 is duplicated and immediately
   return false.

*/
bool Foo( unsigned const int &number)
{
    int temp = number;
    int digitTable[10]={0};

    while(temp > 0)
    {
        digitTable[temp % 10]++; // Last digit's respective index.
        temp /= 10; // Move to next digit
    }

    for (int i=0; i < 10; i++)
    {
        if (digitTable [i] > 1)
        {
            return false;
        }
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)


ViF*_*iFI 5

这是@Puppy的答案的延伸,这是目前最好的答案.

PS:我试图在@Puppy当前的最佳答案中插入这篇文章作为评论,但不能这样,因为我还没有50分.此处还分享了一些实验数据以获得进一步的帮助.

std :: set和std :: map都是在STL中使用Balanced Binary Search树实现的.因此,只有在这种情况下,两者都会导致O(nlogn)的复杂性.如果使用哈希表,则可以实现更好的性能.std :: unordered_map提供基于哈希表的实现,以加快搜索速度.我尝试了所有三个实现,并发现使用std :: unordered_map的结果比std :: set和std :: map更好.结果和代码在下面分享.图像是LeetCode在解决方案上测量的性能快照.

bool hasDuplicate(vector<int>& nums) {
    size_t count = nums.size();
    if (!count)
        return false;
    std::unordered_map<int, int> tbl;
    //std::set<int> tbl;
    for (size_t i = 0; i < count; i++) {
        if (tbl.find(nums[i]) != tbl.end())
            return true;
        tbl[nums[i]] = 1;
        //tbl.insert(nums[i]);
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

unordered_map性能(此处运行时间为52毫秒) 在此输入图像描述

设置/映射性能 在此输入图像描述