Time complexity is supposed to be \$O(n \cdot \log(n))\$ and space complexity is supposed to be \$O(1)\$. Neither the elements of the container nor the container should be modified.
// Copyright [2015] <none>
#include <cstdlib>
#include <cstddef>
#include <cassert>
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>
#include <random>
#include <algorithm>
#include <limits>
// #define NODEBUG
/**
* Finds one duplicate number in container where the largest number in the
* container is smaller than the size of the container.
*/
template <class It>
It FindOneDuplicate(It first, It last) {
int n = static_cast<int>(std::distance(first, last) - 1);
int range_start = 1;
int range_end = n / 2;
while (true) {
next_range:
int range_size = range_end - range_start + 1;
int count = 0;
for (auto current{first}; current != last; ++current) {
int element = *current;
if (element >= range_start && element <= range_end) {
++count;
if (count > range_size) {
n = range_end;
range_end = (n + range_start) / 2;
if (range_size == 1) {
return current;
}
// break and continue
goto next_range;
}
}
}
// This should never happen
assert(range_end != n);
range_start = range_end + 1;
range_end = n;
}
}
// This is just a test run
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <N>" << std::endl;
return EXIT_FAILURE;
}
int n =
static_cast<int>(std::strtol(argv[1], static_cast<char**>(nullptr), 10));
assert(n > 0 && n < std::numeric_limits<int>::max());
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<> dist(1, n);
std::size_t size{static_cast<std::size_t>(n + 1)};
std::vector<int> elements(size);
// Fill and increment except last
std::iota(elements.begin(), elements.end() - 1, 1);
// Fill last with random value [1..N]
elements.back() = dist(generator);
// Shuffle elements
std::shuffle(elements.begin(), elements.end(), generator);
auto duplicate = FindOneDuplicate(elements.begin(), elements.end());
for (const auto& element : elements) {
bool isduplicate = element == *duplicate;
if (isduplicate) {
// bold;red
std::cout << "\033[1;31m";
}
std::cout << element;
if (isduplicate) {
// reset
std::cout << "\033[0m";
}
if (&element != &elements.back()) {
std::cout << ", ";
}
}
std::cout << std::endl;
return EXIT_SUCCESS;
}
Since this is my first real piece of C++ code I'd love to get some code review before I start working on any open source projects.
Note that I'm trying to follow the Google C++ style guide here.