Skip to content

Instantly share code, notes, and snippets.

@sjolsen
Last active January 2, 2016 19:19
Show Gist options
  • Save sjolsen/8349471 to your computer and use it in GitHub Desktop.
Save sjolsen/8349471 to your computer and use it in GitHub Desktop.
A solution to https://www.hackerrank.com/challenges/xor-key, with input validation thrown in for kicks.
#include <vector>
#include <iterator>
#ifndef NDEBUG
static int nth_input = 0;
#endif
using integer = int;
using key_type = std::vector <integer>;
using key_iter = typename key_type::const_iterator;
using input_iter = std::istream_iterator <integer>;
using output_iter = std::ostream_iterator <integer>;
#include <stdexcept>
#include <limits>
#include <cstdio>
#include <cstring>
template <typename T, std::size_t N>
constexpr
std::size_t array_length (T (&) [N])
{ return N; }
class input_range_error
: public std::exception
{
static constexpr
const char format [] = "Expected value in [%d, %d]; got %d";
// Allocate enough space to contain the formatted string. Each value may take up to digits10 + 1
// characters (because digits10 is truncated), plus one for the sign. Subtracting two for the space
// taken by "%d" gives us a requirement of just digits10 more characters per integer.
char what_str [array_length (format) + 3 * std::numeric_limits <integer>::digits10];
public:
input_range_error (integer min, integer max, integer got)
: what_str {"Failed to format what_str"}
{
std::snprintf (what_str, array_length (what_str), format, min, max, got);
}
virtual const char* what () const noexcept override
{
return what_str;
}
virtual ~input_range_error () = default;
};
constexpr
const char input_range_error::format [];
inline
void check_input (integer min, integer max, integer got)
{
if (!(min <= got && got <= max))
throw input_range_error (min, max, got);
}
inline
integer get_input (input_iter& input, input_iter input_end, integer min, integer max)
{
if (input == input_end)
throw std::runtime_error ("Expected input");
auto got = *input++;
check_input (min, max, got);
#ifndef NDEBUG
++nth_input;
#endif
return got;
}
#include <iostream>
#include <algorithm>
integer do_query (integer a, key_iter p, key_iter q)
{
auto index = std::max_element (p, q, [a] (integer x_1, integer x_2)
{
return (a xor x_1) < (a xor x_2);
});
return (a xor *index);
}
template <typename input_iter, typename output_iter>
void do_test (input_iter& input, input_iter input_end, output_iter output)
{
const integer N = get_input (input, input_end, 1, 100000);
const integer Q = get_input (input, input_end, 1, 50000);
static key_type key;
key.resize (N);
for (integer& subkey : key)
subkey = get_input (input, input_end, 0, (1 << 15) - 1); // [0, 2^15)
for (integer query = 1; query <= Q; ++query)
{
const integer a = get_input (input, input_end, 0, (1 << 15) - 1); // [0, 2^15)
const integer p = get_input (input, input_end, 1, N);
const integer q = get_input (input, input_end, p, N);
const auto search_begin = begin (key) + p - 1; // p and q are given as 1-based indices
const auto search_end = begin (key) + q; // Search includes q
*output++ = do_query (a, search_begin, search_end);
}
}
void process_input (std::istream& input_stream, std::ostream& output_stream)
{
auto input = input_iter {input_stream};
auto input_end = input_iter {};
auto output = output_iter {output_stream, "\n"};
const integer T = get_input (input, input_end, 1, 6);
for (integer test_case = 1; test_case <= T; ++test_case)
do_test (input, input_end, output);
if (input != input_end)
throw std::runtime_error ("Unexpected input");
}
#include <fstream>
void xor_key (int argc, const char* const* argv)
{
std::ifstream input_file;
std::ofstream output_file;
std::istream* input;
std::ostream* output;
if (argc < 2 ||
strcmp (argv [1], "-") == 0)
{
input = &std::cin;
}
else
{
input_file.open (argv [1]);
input = &input_file;
}
if (argc < 3 ||
strcmp (argv [2], "-") == 0)
{
output = &std::cout;
}
else
{
output_file.open (argv [2]);
output = &output_file;
}
process_input (*input, *output);
}
int main (int argc, const char* const* argv)
{
try
{
xor_key (argc, argv);
}
catch (const input_range_error& e)
{
std::cerr << e.what () << std::endl;
#ifndef NDEBUG
std::cerr << "At input " << nth_input << std::endl;
#endif
return EXIT_FAILURE;
}
catch (const std::exception& e)
{
std::cerr << e.what () << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment