Last active
January 2, 2016 19:19
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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