我在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
它完美无缺,但我想知道是否有更优雅或更有效的检查方式。
答案 0 :(得分: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--;
}
}
我也推荐使用std :: set - 没有重复项。
答案 1 :(得分:9)
以下解决方案基于对数字进行排序,然后删除重复项:
#include <algorithm>
int main()
{
int userNumbers[6];
// ...
int* end = userNumbers + 6;
std::sort(userNumbers, end);
bool containsDuplicates = (std::unique(userNumbers, end) != end);
}
答案 2 :(得分:7)
确实,最快,到目前为止,我可以看到最优雅的方法如上所述:
std::vector<int> tUserNumbers;
// ...
std::set<int> tSet(tUserNumbers.begin(), tUserNumbers.end());
std::vector<int>(tSet.begin(), tSet.end()).swap(tUserNumbers);
是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());
仍为O(n log n)并保持tUserNumbers
中元素的原始排序。
干杯,
保
答案 3 :(得分:6)
您可以添加集合中的所有元素,并在添加时检查它是否已存在。那将更加优雅和高效。
答案 4 :(得分: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;
}
答案 5 :(得分: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;
}
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;
}
unordered_map 效果(此处运行时间为52毫秒)
答案 6 :(得分:4)
没关系,特别适合小阵列长度。如果数组更大,我会使用更高效的aproaches(小于n ^ 2/2比较) - 请参阅DeadMG的答案。
您的代码的一些小修正:
int j = i
写int j = i +1
而您可以省略if(j != i)
测试i
声明之外声明for
变量。答案 7 :(得分:1)
//std::unique(_copy) requires a sorted container.
std::sort(cont.begin(), cont.end());
//testing if cont has duplicates
std::unique(cont.begin(), cont.end()) != cont.end();
//getting a new container with no duplicates
std::unique_copy(cont.begin(), cont.end(), std::back_inserter(cont2));
答案 8 :(得分:1)
#include<iostream>
#include<algorithm>
int main(){
int arr[] = {3, 2, 3, 4, 1, 5, 5, 5};
int len = sizeof(arr) / sizeof(*arr); // Finding length of array
std::sort(arr, arr+len);
int unique_elements = std::unique(arr, arr+len) - arr;
if(unique_elements == len) std::cout << "Duplicate number is not present here\n";
else std::cout << "Duplicate number present in this array\n";
return 0;
}
答案 9 :(得分:0)
如@underscore_d所述,一种优雅而有效的解决方案将是
#include <algorithm>
#include <vector>
template <class Iterator>
bool has_duplicates(Iterator begin, Iterator end) {
using T = typename std::iterator_traits<Iterator>::value_type;
std::vector<T> values(begin, end);
std::sort(values.begin(), values.end());
return (std::adjacent_find(values.begin(), values.end()) != values.end());
}
int main() {
int user_ids[6];
// ...
std::cout << has_duplicates(user_ids, user_ids + 6) << std::endl;
}
答案 10 :(得分:0)
我认为@Michael Jaison G的解决方案非常出色,为了避免排序,我对他的代码做了一些修改。 (通过使用unordered_set,该算法可能会更快一点。)
template <class Iterator>
bool isDuplicated(Iterator begin, Iterator end) {
using T = typename std::iterator_traits<Iterator>::value_type;
std::unordered_set<T> values(begin, end);
std::size_t size = std::distance(begin,end);
return size != values.size();
}
答案 11 :(得分:0)
快速O(N)时空解决方案 重复时先返回
template <typename T>
bool containsDuplicate(vector<T>& items) {
return any_of(items.begin(), items.end(), [s = unordered_set<T>{}](const auto& item) mutable {
return !s.insert(item).second;
});
}