From c874493d51e266696dd82e25e1192ab6e6affff6 Mon Sep 17 00:00:00 2001 From: Ivan-Voronyuk Date: Mon, 23 Jun 2025 06:08:55 +0300 Subject: [PATCH 1/2] Solution first version Solution to 8 tasks. Some code lacks formatting. Will probably be fixed in future versions. --- task_01/src/main.cpp | 8 +- task_01/src/solution.cpp | 40 ++++ task_01/src/solution.hpp | 11 + task_01/src/test.cpp | 62 ++++- task_02/src/stack.cpp | 41 +++- task_02/src/stack.hpp | 10 +- task_02/src/test.cpp | 35 ++- task_03/src/solution.cpp | 34 +++ task_03/src/solution.hpp | 4 + task_03/src/test.cpp | 30 ++- task_03/src/topology_sort.cpp | 1 - task_03/src/topology_sort.hpp | 1 - task_04/src/queue.cpp | 37 +++ task_04/src/queue.hpp | 21 ++ task_04/src/solution.cpp | 26 +++ task_04/src/solution.hpp | 6 + task_04/src/test.cpp | 67 +++++- task_05/src/sorting.cpp | 98 ++++++++ task_05/src/sorting.hpp | 13 ++ task_05/src/test.cpp | 42 +++- task_06/src/k-stat.cpp | 40 ++++ task_06/src/k-stat.hpp | 4 + task_06/src/test.cpp | 33 ++- task_07/src/test.cpp | 63 +++++- task_07/src/tree.cpp | 410 ++++++++++++++++++++++++++++++++++ task_07/src/tree.hpp | 60 +++++ task_08/src/hashtable.cpp | 67 ++++++ task_08/src/hashtable.hpp | 29 +++ task_08/src/test.cpp | 143 +++++++++++- 29 files changed, 1405 insertions(+), 31 deletions(-) create mode 100644 task_01/src/solution.cpp create mode 100644 task_01/src/solution.hpp create mode 100644 task_03/src/solution.cpp create mode 100644 task_03/src/solution.hpp delete mode 100644 task_03/src/topology_sort.cpp delete mode 100644 task_03/src/topology_sort.hpp create mode 100644 task_04/src/queue.cpp create mode 100644 task_04/src/queue.hpp create mode 100644 task_04/src/solution.cpp create mode 100644 task_04/src/solution.hpp create mode 100644 task_05/src/sorting.cpp create mode 100644 task_05/src/sorting.hpp create mode 100644 task_06/src/k-stat.cpp create mode 100644 task_06/src/k-stat.hpp create mode 100644 task_07/src/tree.cpp create mode 100644 task_07/src/tree.hpp create mode 100644 task_08/src/hashtable.cpp create mode 100644 task_08/src/hashtable.hpp diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 0e4393b..de0287d 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -1,3 +1,9 @@ #include -int main() { return 0; } +#include "solution.hpp" + +int main() { + std::cout << (BinarySearchGEQ({1, 2, 3, 4, 5}, 1, 0, 4) == 0) << std::endl; + std::cout << (BinarySearchGEQ({1, 2, 3, 4, 5}, 5, 0, 4) == 4) + << std::endl; // Stack [] +} diff --git a/task_01/src/solution.cpp b/task_01/src/solution.cpp new file mode 100644 index 0000000..784699d --- /dev/null +++ b/task_01/src/solution.cpp @@ -0,0 +1,40 @@ +#include "solution.hpp" + +#include + +// Binary search for greater-or-equal element +// Explicitly requires and bounds to support searching in +// subarray +int BinarySearchGEQ(const std::vector& arr, int target, int left, + int right) { + while (left < right) { + int mid = left + (right - left + 1) / 2; + if (arr[mid] > target) { + right = mid - 1; + } else { + left = mid; + } + } + return left; +} + +// Custom error code +struct PairNotFound {}; + +/* + * Algorithm description: + * run index over array + * search for that is greater or equal to + * ! seach range is (, ] + */ +std::pair FindPairMatchSum(const std::vector& arr, int target) { + unsigned int left = 0; + unsigned int right = + BinarySearchGEQ(arr, target - arr[left], 0, arr.size() - 1); + while (left < arr.size() - 1 && arr[left] + arr[left + 1] < target) { + if (arr[left] + arr[right] == target) return {arr[left], arr[right]}; + left += 1; + right = BinarySearchGEQ(arr, target - arr[left], left, right); + } + throw std::runtime_error("Failed to find sutable pair"); +} diff --git a/task_01/src/solution.hpp b/task_01/src/solution.hpp new file mode 100644 index 0000000..17f2bc3 --- /dev/null +++ b/task_01/src/solution.hpp @@ -0,0 +1,11 @@ +#ifndef SOLUTION_HPP +#define SOLUTION_HPP + +#include +#include + +std::pair FindPairMatchSum(const std::vector& arr, int target); +int BinarySearchGEQ(const std::vector& arr, int target, int left, + int right); + +#endif diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..c7ebc85 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,61 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] -} \ No newline at end of file +#include +#include +#include + +#include "solution.hpp" + +TEST(BinarySearchSubtest, EdgeCases) { + ASSERT_EQ(BinarySearchGEQ({1, 2, 3, 4, 5}, 1, 0, 4), 0); // Stack [] + ASSERT_EQ(BinarySearchGEQ({1, 2, 3, 4, 5}, 5, 0, 4), 4); // Stack [] +} +TEST(BinarySearchSubtest, MiddleCases) { + ASSERT_EQ(BinarySearchGEQ({0, 1, 2, 3, 4, 5}, 3, 0, 5), 3); // Stack [] + ASSERT_EQ(BinarySearchGEQ({0, 1, 2, 3, 4, 5}, 4, 0, 5), 4); // Stack [] +} +TEST(BinarySearchSubtest, Inequality) { + ASSERT_EQ(BinarySearchGEQ({0, 2, 4, 6, 8, 9}, 31, 0, 5), 5); // Stack [] + ASSERT_EQ(BinarySearchGEQ({0, 2, 3, 6, 7, 9}, 5, 0, 5), 2); // Stack [] + ASSERT_EQ(BinarySearchGEQ({1, 2, 3, 6, 7, 9}, 0, 0, 5), 0); // Stack [] +} +TEST(SolutionTest, Random100of1000x1000) { + std::vector arr(100); + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist_gen(0, 1000); + std::uniform_int_distribution dist_sample(0, 99); + + for (int i = 0; i < 1000; ++i) { + // gen + for (int i = 0; i < 100; ++i) arr[i] = dist_gen(rng); + // sort array according to task + std::sort(arr.begin(), arr.end()); + + // sample + int first_sample = dist_sample(rng); + int second_sample = first_sample; + while (second_sample == first_sample) second_sample = dist_sample(rng); + + // target sum + int sum = arr[first_sample] + arr[second_sample]; + + // get answer + auto [res_first, res_second] = FindPairMatchSum(arr, sum); + + // compare + // ! we might get other indexes then A & B we sampled. + // Let's test the sum and the existance of elements + ASSERT_EQ(res_first + res_second, sum); + + auto search_iterator = arr.begin(); + while (search_iterator != arr.end() && *search_iterator != res_first) + ++search_iterator; + ASSERT_NE(search_iterator, arr.end()); + search_iterator = arr.begin(); + while (search_iterator != arr.end() && *search_iterator != res_second) + ++search_iterator; + ASSERT_NE(search_iterator, arr.end()); + } +} diff --git a/task_02/src/stack.cpp b/task_02/src/stack.cpp index 8ca8990..f405950 100644 --- a/task_02/src/stack.cpp +++ b/task_02/src/stack.cpp @@ -1,21 +1,46 @@ #include "stack.hpp" #include +#include -void Stack::Push(int value) { data_.push(value); } +// ----------------------------------- STACK ----------------------------------- + +Stack::Stack(unsigned int reserve) : data_() { data_.reserve(reserve); } + +void Stack::Push(int value) { data_.push_back(value); } int Stack::Pop() { - auto result = data_.top(); - data_.pop(); + if (data_.size() == 0) + throw std::runtime_error("trying to pop from empty stack"); + auto result = data_[data_.size() - 1]; + data_.pop_back(); return result; } -void MinStack::Push(int value) { data_.push_back(value); } +int Stack::GetTop() { + if (data_.size() == 0) + throw std::runtime_error("trying get something from empty stack"); + return data_[data_.size() - 1]; +} + +bool Stack::IsEmpy() { return data_.size() == 0; } + +// --------------------------------- MIN STACK --------------------------------- + +MinStack::MinStack(unsigned int reserve) : data_(reserve), min_(reserve) {} + +void MinStack::Push(int value) { + data_.Push(value); + + if (min_.IsEmpy()) + min_.Push(value); + else + min_.Push(std::min(min_.GetTop(), value)); +} int MinStack::Pop() { - auto result = data_.back(); - data_.pop_back(); - return result; + min_.Pop(); + return data_.Pop(); } -int MinStack::GetMin() { return *std::min_element(data_.begin(), data_.end()); } \ No newline at end of file +int MinStack::GetMin() { return min_.GetTop(); } diff --git a/task_02/src/stack.hpp b/task_02/src/stack.hpp index 138ec40..bb8c953 100644 --- a/task_02/src/stack.hpp +++ b/task_02/src/stack.hpp @@ -5,19 +5,25 @@ class Stack { public: + Stack(unsigned int reserve = 0); void Push(int value); int Pop(); + // some handy extensions + int GetTop(); // sometimes called Peek but GetTop is more self-describing + bool IsEmpy(); private: - std::stack data_; + std::vector data_; }; class MinStack { public: + MinStack(unsigned int reserve = 0); void Push(int value); int Pop(); int GetMin(); private: - std::vector data_; + Stack data_; + Stack min_; }; diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 54e7ce9..0b11d7d 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,7 +1,8 @@ #include -#include +#include +#include #include "stack.hpp" @@ -39,4 +40,34 @@ TEST(MinStackTest, Simple) { ASSERT_EQ(stack.GetMin(), 1); ASSERT_EQ(stack.Pop(), 3); // Stack [1] ASSERT_EQ(stack.Pop(), 1); // Stack [] -} \ No newline at end of file +} + +TEST(MinStackTest, Random) { + MinStack mstack; + + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist(-1000000, 1000000); + + for (unsigned int repeation = 0; repeation < 1000; ++repeation) { + constexpr unsigned int N = 1000; + std::array min; + + min[0] = dist(rng); + mstack.Push(min[0]); + ASSERT_EQ(min[0], mstack.GetMin()); // forward pass - zero + for (unsigned int i = 1; i < N; ++i) { + int value = dist(rng); + + min[i] = std::min(min[i - 1], value); + mstack.Push(value); + + ASSERT_EQ(min[i], mstack.GetMin()); // forward pass + } + for (int i = N - 1; i >= 0; --i) { + ASSERT_EQ(mstack.GetMin(), min[i]); // backward pass + + mstack.Pop(); + } + } +} diff --git a/task_03/src/solution.cpp b/task_03/src/solution.cpp new file mode 100644 index 0000000..4488f40 --- /dev/null +++ b/task_03/src/solution.cpp @@ -0,0 +1,34 @@ +#include "solution.hpp" + +#include +#include + +std::vector DaysToWarming(std::vector temps) { + std::stack temp_steps; + std::stack temp_steps_days; + + std::vector res(temps.size()); + + for (int day = temps.size() - 1; day >= 0; --day) { + while (!temp_steps.empty() && temp_steps.top() <= temps[day]) { + temp_steps.pop(); + temp_steps_days.pop(); + } + + if (!temp_steps.empty()) { + // + // 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 + // | c | 1 | 2 | 3 | + | + // + // 6 - 2 = 4 = 3 + current + res[day] = temp_steps_days.top() - day; + } else { + res[day] = 0; // there won't be any warmer days + } + + temp_steps.push(temps[day]); + temp_steps_days.push(day); + } + + return res; +} diff --git a/task_03/src/solution.hpp b/task_03/src/solution.hpp new file mode 100644 index 0000000..14d361e --- /dev/null +++ b/task_03/src/solution.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include +std::vector DaysToWarming(std::vector temps); diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..7fc4d0a 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,32 @@ #include -#include "topology_sort.hpp" +#include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "solution.hpp" + +TEST(DaysToWarming, Case_One) { + /* + * .-------------------x + * 8 # .-------x + * 7 # # + * 6 # .--8--->### + * 5 #1# ##### .-.---x + * 4 ### .2##### #1#.-.x + * 3 ###321#1##### ####1## + * 2 #############1####### + * 1 ##################### + * + * 012345678901234567890 + */ + + std::vector temps{8, 4, 5, 2, 2, 2, 3, 2, 5, 5, 6, + 6, 7, 1, 4, 3, 4, 3, 2, 3, 3}; + std::vector exprected_res{0, 1, 8, 3, 2, 1, 2, 1, 2, 1, 2, + 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}; + auto res = DaysToWarming(temps); + + ASSERT_EQ(res.size(), exprected_res.size()); + for (int i = 0; i < res.size(); ++i) + ASSERT_EQ(res[i], exprected_res[i]) << "Result wrong at index " << i; } diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp deleted file mode 100644 index e53f670..0000000 --- a/task_03/src/topology_sort.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "topology_sort.hpp" diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp deleted file mode 100644 index 6f70f09..0000000 --- a/task_03/src/topology_sort.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/task_04/src/queue.cpp b/task_04/src/queue.cpp new file mode 100644 index 0000000..a126d80 --- /dev/null +++ b/task_04/src/queue.cpp @@ -0,0 +1,37 @@ +#include "queue.hpp" + +MinQueue::MinQueue() + : data_queue(), min_val_queue(), min_pos_queue(), already_pushed(0) {} + +void MinQueue::Push(int value) { + data_queue.push(value); + + // front --> newer --> back + // front --> greater --> back + // delete everything that is incorrect) + while (min_val_queue.size() > 0 && min_val_queue.back() > value) { + min_val_queue.pop_back(); + min_pos_queue.pop_back(); + } + min_val_queue.push_back(value); + min_pos_queue.push_back(already_pushed++); +} + +int MinQueue::Pull() { + int pull_pos = already_pushed - data_queue.size(); + if (min_pos_queue.front() == pull_pos) { + min_val_queue.pop_front(); + min_pos_queue.pop_front(); + } + int res = data_queue.front(); + data_queue.pop(); + return res; +} + +int MinQueue::Front() { return data_queue.front(); } +int MinQueue::Back() { return data_queue.back(); } + +int MinQueue::GetMin() { return min_val_queue.front(); } +int MinQueue::GetMinPos() { return min_pos_queue.front(); } + +bool MinQueue::IsEmpty() { return data_queue.empty(); } diff --git a/task_04/src/queue.hpp b/task_04/src/queue.hpp new file mode 100644 index 0000000..bd29a5f --- /dev/null +++ b/task_04/src/queue.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +class MinQueue { + private: + std::queue data_queue; + std::deque min_val_queue; + std::deque min_pos_queue; + unsigned int already_pushed; + + public: + MinQueue(); + void Push(int value); + int Pull(); + int Front(); + int Back(); + int GetMin(); + int GetMinPos(); + bool IsEmpty(); +}; diff --git a/task_04/src/solution.cpp b/task_04/src/solution.cpp new file mode 100644 index 0000000..ec78ef5 --- /dev/null +++ b/task_04/src/solution.cpp @@ -0,0 +1,26 @@ +#include "solution.hpp" + +#include +#include + +std::vector FishPerDay(std::vector prices, int k) { + // the fish can't lay for more than prices.size() days + k = std::min((int)prices.size(), k); + std::vector res(prices.size()); + MinQueue queue; + + int day = 0; + + for (; day < k; ++day) { + queue.Push(prices[day]); + res[queue.GetMinPos()] += 1; + } + + for (; day < prices.size(); ++day) { + queue.Pull(); + queue.Push(prices[day]); + res[queue.GetMinPos()] += 1; + } + + return res; +} diff --git a/task_04/src/solution.hpp b/task_04/src/solution.hpp new file mode 100644 index 0000000..1a277a7 --- /dev/null +++ b/task_04/src/solution.hpp @@ -0,0 +1,6 @@ +#pragma once +#include + +#include_next "queue.hpp" + +std::vector FishPerDay(std::vector prices, int k); diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..622b643 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,69 @@ #include +#include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include +#include + +#include "queue.hpp" +#include "solution.hpp" + +TEST(MinQueue, Random) { + MinQueue queue; + + std::random_device dev; + std::mt19937 rng(dev()); + + std::uniform_int_distribution distr_gen(-1000, 1000); + std::uniform_int_distribution distr_action(0, 100); + + for (uint repetion = 0; repetion < 1000; ++repetion) { + int should_remain = distr_action(rng) + 1; + int should_pull = distr_action(rng); + + for (uint i = 0; i < should_remain + should_pull; ++i) + queue.Push(distr_gen(rng)); + for (uint i = 0; i < should_pull; ++i) queue.Pull(); + + int queue_min = queue.GetMin(); + int actual_min = queue.Pull(); + while (!queue.IsEmpty()) actual_min = std::min(actual_min, queue.Pull()); + + ASSERT_EQ(queue_min, actual_min); + } +} + +TEST(FishPerDay, EdgeSimple) { + std::vector prices{1, 2, 3, 2, 3}; + std::vector expected_res{5, 0, 0, 0, 0}; + + auto actual_res = FishPerDay(prices, 99); + + ASSERT_EQ(expected_res.size(), actual_res.size()); + for (uint i = 0; i < expected_res.size(); ++i) + ASSERT_EQ(actual_res[i], expected_res[i]) << "res differ at pos " << i; +} + +TEST(FishPerDay, EdgeComplex) { + std::vector prices{2, 3, 1, 2, 3}; + std::vector expected_res{2, 0, 3, 0, 0}; + + auto actual_res = FishPerDay(prices, 99); + + ASSERT_EQ(expected_res.size(), actual_res.size()); + for (uint i = 0; i < expected_res.size(); ++i) + ASSERT_EQ(actual_res[i], expected_res[i]) << "res differ at pos " << i; +} + +TEST(FishPerDay, Complex) { + int k = 3; + std::vector prices{1, 6, 5, 7, 9, 5, 3, 6, 5, 9, 11, 8, 2}; + std::vector expected_res{3, 0, 2, 0, 0, 1, 3, 0, 2, 0, 0, 1, 1}; + + auto actual_res = FishPerDay(prices, k); + + ASSERT_EQ(expected_res.size(), actual_res.size()); + for (uint i = 0; i < expected_res.size(); ++i) + ASSERT_EQ(actual_res[i], expected_res[i]) << "res differ at pos " << i; } diff --git a/task_05/src/sorting.cpp b/task_05/src/sorting.cpp new file mode 100644 index 0000000..5a820b0 --- /dev/null +++ b/task_05/src/sorting.cpp @@ -0,0 +1,98 @@ +#include "sorting.hpp" + +#include + +#include +#include +#include +#include + +using namespace sortings; + +inline void sort2(int& A, int& B) { + if (A > B) std::swap(A, B); +} +inline void sort3(int& A, int& B, int& C) { + sort2(A, B); + sort2(B, C); + sort2(A, B); +} + +inline int median3(int A, int B, int C) { + sort3(A, B, C); + return B; +} + +std::vector sortings::qsort(std::vector arr) { + return qsort_inplace(arr); +} +std::vector& sortings::qsort_inplace(std::vector& arr) { + struct Interval { + int L; + int R; + }; + + std::stack> stack; + stack.push(Interval{0, static_cast(arr.size() - 1)}); + + while (not stack.empty()) { + auto bounds = stack.top(); + stack.pop(); + + if (bounds.R - bounds.L < 1) { + continue; + } + if (bounds.R - bounds.L == 1) { + sort2(arr[bounds.L], arr[bounds.R]); + continue; + } + if (bounds.R - bounds.L == 2) { + sort3(arr[bounds.L], arr[bounds.L + 1], arr[bounds.L + 2]); + continue; + } + + auto [L, R] = bounds; + int M = median3(arr[L], arr[(L + R) / 2], arr[R]); + while (true) { + while (arr[L] < M) L += 1; + while (arr[R] > M) R -= 1; + if (L < R) + std::swap(arr[L++], arr[R--]); + else + break; + } + stack.push(Interval{bounds.L, R}); + stack.push(Interval{R + 1, bounds.R}); + } + + return arr; +} + +std::vector sortings::heapsort(std::vector arr) { + return heapsort_inplace(arr); +} + +inline void heapify(std::vector& arr, uint I, uint L) { + uint next = I; + do { + I = next; + // (i+1)*2-1 = 2*i + 2 - 1 = 2*i-1 + // (i+1)*2+1-1 = 2*i+2 + if (2 * I + 1 < L && arr[2 * I + 1] > arr[next]) next = 2 * I + 1; + if (2 * I + 2 < L && arr[2 * I + 2] > arr[next]) next = 2 * I + 2; + if (next != 0) std::swap(arr[I], arr[next]); + } while (next != I); +} + +std::vector& sortings::heapsort_inplace(std::vector& arr) { + if (arr.size() == 1) return arr; + // build heap + for (int i = arr.size() / 2; i >= 0; --i) { + heapify(arr, i, arr.size()); + } + for (int L = arr.size() - 1; L >= 1; --L) { + std::swap(arr[0], arr[L]); + heapify(arr, 0, L); + } + return arr; +} diff --git a/task_05/src/sorting.hpp b/task_05/src/sorting.hpp new file mode 100644 index 0000000..dfae397 --- /dev/null +++ b/task_05/src/sorting.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace sortings { + +std::vector qsort(std::vector arr); +std::vector& qsort_inplace(std::vector& arr); + +std::vector heapsort(std::vector arr); +std::vector& heapsort_inplace(std::vector& arr); + +} // namespace sortings diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..3f7f7cb 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,44 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include +#include + +#include "sorting.hpp" + +TEST(QSort, Binary16) { + std::vector arr(16); + for (uint i = 0; i < (1 << 16); ++i) { + for (uint j = 0; j < 16; ++j) arr[j] = (i >> j) & 1; + + sortings::qsort_inplace(arr); + + int target_res = (1 << std::popcount(i)) - 1; + int actual_res = 0; + + for (uint j = 0; j < 16; ++j) actual_res = (actual_res << 1) | arr[j]; + + ASSERT_EQ(std::format("{:016b}", target_res), + std::format("{:016b}", actual_res)) + << std::format("sorting failed on binary pattern {} {:016b}", i, i); + } +} + +TEST(HeapSort, Binary16) { + std::vector arr(16); + for (uint i = 0; i < (1 << 16); ++i) { + for (uint j = 0; j < 16; ++j) arr[j] = (i >> (15 - j)) & 1; + + sortings::heapsort_inplace(arr); + + int target_res = (1 << std::popcount(i)) - 1; + int actual_res = 0; + + for (uint j = 0; j < 16; ++j) actual_res = (actual_res << 1) | arr[j]; + + ASSERT_EQ(std::format("{:016b}", target_res), + std::format("{:016b}", actual_res)) + << std::format("sorting failed on binary pattern {} {:016b}", i, i); + } } diff --git a/task_06/src/k-stat.cpp b/task_06/src/k-stat.cpp new file mode 100644 index 0000000..83aa029 --- /dev/null +++ b/task_06/src/k-stat.cpp @@ -0,0 +1,40 @@ +#include "k-stat.hpp" + +#include + +inline void sort3(int& A, int& B, int& C) { + if (A > B) std::swap(A, B); + if (B > C) std::swap(B, C); + if (A > B) std::swap(A, B); +} +inline int median3(int A, int B, int C) { + sort3(A, B, C); + return B; +} + +int KOrdinalStatistics(std::vector data, int k) { + struct Segment { + int L; + int R; + }; + + Segment segment{0, static_cast(data.size() - 1)}; + + while (segment.L < segment.R) { + auto [L, R] = segment; + int M = median3(data[L], data[(L + R) / 2], data[R]); + while (true) { + while (data[L] < M) L += 1; + while (data[R] > M) R -= 1; + if (L < R) + std::swap(data[L++], data[R--]); + else + break; + } + if (k <= R) + segment.R = R; + else if (k > R) + segment.L = R + 1; + } + return data[k]; +} diff --git a/task_06/src/k-stat.hpp b/task_06/src/k-stat.hpp new file mode 100644 index 0000000..2c1a4b9 --- /dev/null +++ b/task_06/src/k-stat.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include +int KOrdinalStatistics(std::vector data, int k); diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..6804f98 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,35 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include +#include + +#include "k-stat.hpp" + +TEST(KOrdinalStatistics, Simple16) { + std::vector arr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + for (uint i = 0; i < 10; ++i) + ASSERT_EQ(KOrdinalStatistics(arr, i), i); // Stack [] +} +TEST(KOrdinalStatistics, Simple23) { + std::vector arr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; + for (uint i = 0; i < 23; ++i) + ASSERT_EQ(KOrdinalStatistics(arr, i), i); // Stack [] +} + +TEST(KOrdinalStatistics, SimpleShuffled) { + const int N = 100; + + std::random_device dev; + std::mt19937 rng(dev()); + + std::vector arr(N); + for (uint i = 0; i < N; ++i) arr[i] = i; + + std::shuffle(arr.begin(), arr.end(), rng); + + for (uint i = 0; i < N; ++i) + ASSERT_EQ(KOrdinalStatistics(arr, i), i); // Stack [] } diff --git a/task_07/src/test.cpp b/task_07/src/test.cpp index 5e11617..f6c06ce 100644 --- a/task_07/src/test.cpp +++ b/task_07/src/test.cpp @@ -1,6 +1,65 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "tree.hpp" + +TEST(SplayTree, Simple) { + SplayTree tree; + + tree.Insert(0, 0); + + ASSERT_EQ(tree.SearchExact(0), 0); + + tree.Insert(1, 1); + tree.Insert(2, 2); + tree.Insert(3, 3); + tree.Insert(4, 4); + + ASSERT_EQ(tree.SearchExact(1), 1); + ASSERT_EQ(tree.SearchExact(2), 2); + ASSERT_EQ(tree.SearchExact(3), 3); + ASSERT_EQ(tree.SearchExact(4), 4); + + ASSERT_EQ(tree.SearchMin().second, 0); + ASSERT_EQ(tree.SearchMax().second, 4); +} + +TEST(SplayTree, SimpleDelete) { + SplayTree tree; + + tree.Insert(0, 0); + + ASSERT_EQ(tree.SearchExact(0), 0); + + tree.Insert(1, 1); + tree.Insert(2, 2); + tree.Insert(3, 3); + tree.Insert(4, 4); + + ASSERT_EQ(tree.SearchExact(1), 1); + ASSERT_EQ(tree.SearchExact(2), 2); + ASSERT_EQ(tree.SearchExact(3), 3); + ASSERT_EQ(tree.SearchExact(4), 4); + + ASSERT_EQ(tree.SearchMin().second, 0); + ASSERT_EQ(tree.SearchMax().second, 4); + + tree.Delete(0); + + ASSERT_EQ(tree.SearchExact(1), 1); + ASSERT_EQ(tree.SearchExact(2), 2); + ASSERT_EQ(tree.SearchExact(3), 3); + ASSERT_EQ(tree.SearchExact(4), 4); + + ASSERT_EQ(tree.SearchMin().second, 1); + ASSERT_EQ(tree.SearchMax().second, 4); + + tree.Delete(3); + tree.Delete(4); + + ASSERT_EQ(tree.SearchExact(1), 1); + ASSERT_EQ(tree.SearchExact(2), 2); + + ASSERT_EQ(tree.SearchMin().second, 1); + ASSERT_EQ(tree.SearchMax().second, 2); } diff --git a/task_07/src/tree.cpp b/task_07/src/tree.cpp new file mode 100644 index 0000000..4048328 --- /dev/null +++ b/task_07/src/tree.cpp @@ -0,0 +1,410 @@ +#include "tree.hpp" + +#include + +// ----------------------------------- NODE ------------------------------------ + +SplayTree::SplayTreeNode::SplayTreeNode(int key, int value) + : key(key), value(value) {} + +void SplayTree::SplayTreeNode::Rot2(SplayTree::SplayTreeNode* root, + SplayTree::SplayTreeNode* lower, + SplayTree::SplayTreeNode* higher) { + SplayTree::SplayTreeNode *A, *B, *C; + if (lower->key < higher->key) { + // h + // l C + // A B + A = lower->L; + B = lower->R; + C = higher->R; + // l + // A h + // B C + lower->L = A; + lower->R = higher; + higher->L = B; + higher->R = C; + } else { + // h + // A l + // B C + A = higher->L; + B = lower->L; + C = lower->R; + // l + // h C + // A B + lower->L = higher; + higher->L = A; + higher->R = B; + lower->R = C; + } + if (root) { + if (root->key > lower->key) + root->L = lower; + else + root->R = lower; + } +} +void SplayTree::SplayTreeNode::Rot3(SplayTree::SplayTreeNode* root, + SplayTree::SplayTreeNode* lower, + SplayTree::SplayTreeNode* middle, + SplayTree::SplayTreeNode* higher) { + SplayTree::SplayTreeNode *A, *B, *C, *D; + + if (lower->key < middle->key && middle->key < higher->key) { + /* + * h + * m' 'D + * l' 'C + * A"B + */ + A = lower->L; + B = lower->R; + C = middle->R; + D = higher->R; + /* + * l + * A' 'm + * B' 'h + * C"D + */ + lower->L = A; + lower->R = middle; + middle->L = B; + middle->R = higher; + higher->L = C; + higher->R = D; + } else if (higher->key < middle->key && middle->key < lower->key) { + /* + * h + * A' 'm + * B' 'l + * C"D + */ + A = higher->L; + B = middle->L; + C = lower->L; + D = lower->R; + /* + * l + * m' 'D + * h' 'C + * A"B + */ + higher->L = A; + higher->R = B; + middle->L = higher; + middle->R = C; + lower->L = middle; + lower->R = D; + } else if (middle->key < lower->key && lower->key < higher->key) { + /* + * h + * m' 'D + * A' 'l + * B"C + */ + A = middle->L; + B = lower->L; + C = lower->R; + D = higher->R; + /* + * l + * m' 'h + * A"B C"D + */ + lower->L = middle; + lower->R = higher; + middle->L = A; + middle->R = B; + higher->L = C; + higher->R = D; + } else if (higher->key < lower->key && lower->key < middle->key) { + /* + * h + * A' 'm + * l' 'D + * B"C + */ + A = higher->L; + B = lower->L; + C = lower->R; + D = middle->R; + /* + * l + * h' 'm + * A"B C"D + */ + lower->L = higher; + lower->R = middle; + higher->L = A; + higher->R = B; + middle->L = C; + middle->R = D; + } + + if (root) { + if (root->key > lower->key) + root->L = lower; + else + root->R = lower; + } +} + +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::Splay( + SplayTree::SplayTreeNode::PathType& path) { + while (path.size() > 2) { + SplayTree::SplayTreeNode* lower = path.back(); + path.pop_back(); + SplayTree::SplayTreeNode* middle = path.back(); + path.pop_back(); + SplayTree::SplayTreeNode* higher = path.back(); + path.pop_back(); + + Rot3(path.empty() ? nullptr : path.back(), lower, middle, higher); + + path.push_back(lower); + } + if (path.size() == 2) { + SplayTree::SplayTreeNode* lower = path.back(); + path.pop_back(); + SplayTree::SplayTreeNode* higher = path.back(); + path.pop_back(); + Rot2(nullptr, lower, higher); + path.push_back(lower); + } + + return path.back(); +} + +std::pair SplayTree::SplayTreeNode::operator*() { + return {key, value}; +} + +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::SearchExact(int key) { + SplayTree::SplayTreeNode::PathType path; + + SplayTree::SplayTreeNode* node = this; + while (node) { + path.push_back(node); + + if (node->key < key) + node = node->R; + else if (node->key > key) + node = node->L; + else + break; + } + if (node) { + return Splay(path); + } + return nullptr; +} +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::SearchMinGTQ(int key) { + SplayTree::SplayTreeNode::PathType path; + + SplayTree::SplayTreeNode* node = this; + while (node) { + path.push_back(node); + + if (node->key < key) + node = node->R; + else if (node->key > key) + node = node->L; + else + break; + } + while (!path.empty() && path.back()->key < key) path.pop_back(); + + if (path.empty()) return nullptr; + + return Splay(path); +} +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::SearchMaxLEQ(int key) { + PathType path; + + SplayTree::SplayTreeNode* node = this; + while (node) { + path.push_back(node); + + if (node->key < key) + node = node->R; + else if (node->key > key) + node = node->L; + else + break; + } + while (!path.empty() && path.back()->key > key) path.pop_back(); + + if (path.empty()) return nullptr; + + return Splay(path); +} + +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::SearchMax() { + PathType path; + auto node = this; + while (node) { + path.push_back(node); + node = node->R; + } + + return Splay(path); +} +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::SearchMin() { + PathType path; + auto node = this; + while (node) { + path.push_back(node); + node = node->L; + } + + return Splay(path); +} + +std::pair +SplayTree::SplayTreeNode::Split(int key) { + SplayTree::SplayTreeNode* root = SearchMaxLEQ(key); + if (root) { + SplayTree::SplayTreeNode* R = root->R; + root->R = nullptr; + return {root, R}; + } + root = SearchMinGTQ(key); + if (root) { + SplayTree::SplayTreeNode* L = root->L; + root->L = nullptr; + return {L, root}; + } + throw std::runtime_error("WTF?"); +} + +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::Insert( + SplayTree::SplayTreeNode* node) { + auto [L, R] = this->Split(node->key); + + node->L = L; + node->R = R; + + return node; +} +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::Insert(int key, int value) { + return this->Insert(new SplayTree::SplayTreeNode(key, value)); +} + +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::MergeNonintersect( + SplayTree::SplayTreeNode* A, SplayTree::SplayTreeNode* B) { + A = A->SearchMax(); + if (A->key < B->key) { + A->R = B; + return A; + } + A = A->SearchMin(); + if (A->key > B->key) { + A->L = B; + return A; + } + throw std::runtime_error("impossible to merge intersection trees"); +} + +SplayTree::SplayTreeNode* SplayTree::SplayTreeNode::Delete(int key) { + auto elem = this->SearchExact(key); + + if (!elem) throw std::runtime_error("cannot delete non-existing element"); + + SplayTree::SplayTreeNode *L = elem->L, *R = elem->R; + + elem->L = nullptr; + elem->R = nullptr; + delete elem; + + if (L and R) return MergeNonintersect(L, R); + if (L) return L; + if (R) return R; + return nullptr; +} + +SplayTree::SplayTreeNode::~SplayTreeNode() { + if (L) delete L; + if (R) delete R; +} + +// ----------------------------------- TREE ------------------------------------ + +SplayTree::SplayTree(SplayTreeNode* node) : root(node) {} +SplayTree::SplayTree(SplayTree&& old) : root(old.root) { old.root = nullptr; } + +void SplayTree::Insert(int key, int value) { + // Let's not check if the key already exists XD + if (root) + root = root->Insert(key, value); + else + root = new SplayTreeNode(key, value); +} +int SplayTree::SearchExact(int key) { + if (!root) throw std::runtime_error("tree is empty"); + auto res = root->SearchExact(key); + if (!res) { + throw std::runtime_error("key not found"); + } + root = res; + return (*(*res)).second; +} +std::pair SplayTree::SearchMinGTQ(int key) { + if (!root) throw std::runtime_error("tree is empty"); + auto res = root->SearchMinGTQ(key); + if (!res) { + throw std::runtime_error("key not found"); + } + root = res; + return *(*res); +} +std::pair SplayTree::SearchMaxLEQ(int key) { + if (!root) throw std::runtime_error("tree is empty"); + auto res = root->SearchMaxLEQ(key); + if (!res) { + throw std::runtime_error("key not found"); + } + root = res; + return *(*res); +} +std::pair SplayTree::SearchMin() { + if (!root) throw std::runtime_error("tree is empty"); + auto res = root->SearchMin(); + if (!res) { + throw std::runtime_error("key not found"); + } + root = res; + return *(*res); +} +std::pair SplayTree::SearchMax() { + if (!root) throw std::runtime_error("tree is empty"); + auto res = root->SearchMax(); + if (!res) { + throw std::runtime_error("key not found"); + } + root = res; + return *(*res); +} +void SplayTree::Delete(int key) { + if (!root) throw std::runtime_error("tree is empty"); + root = root->Delete(key); +} +std::pair SplayTree::Split(int key) { + if (!root) return {SplayTree(nullptr), SplayTree(nullptr)}; + auto [L, R] = root->Split(key); + return {SplayTree(L), SplayTree(R)}; +} +void SplayTree::Merge(SplayTree&& other) { + if (!root) { + root = other.root; + return; + } + root = SplayTreeNode::MergeNonintersect(root, other.root); +} + +SplayTree::~SplayTree() { + if (root) delete root; +} diff --git a/task_07/src/tree.hpp b/task_07/src/tree.hpp new file mode 100644 index 0000000..aaaa8b5 --- /dev/null +++ b/task_07/src/tree.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +class SplayTree { + private: + class SplayTreeNode { + private: + int key; + int value; + SplayTreeNode* L = nullptr; + SplayTreeNode* R = nullptr; + + typedef std::vector PathType; + + static void Rot3(SplayTreeNode* root, SplayTreeNode* lower, + SplayTreeNode* middle, SplayTreeNode* higher); + static void Rot2(SplayTreeNode* root, SplayTreeNode* lower, + SplayTreeNode* higher); + static SplayTreeNode* Splay(PathType& path); + + public: + SplayTreeNode() = default; + SplayTreeNode(int key, int value); + std::pair operator*(); + SplayTreeNode* SearchExact(int key); + SplayTreeNode* SearchMinGTQ(int key); + SplayTreeNode* SearchMaxLEQ(int key); + SplayTreeNode* SearchMin(); + SplayTreeNode* SearchMax(); + SplayTreeNode* Insert(SplayTreeNode* node); + SplayTreeNode* Insert(int key, int value); + SplayTreeNode* Delete(int key); + static SplayTreeNode* MergeNonintersect(SplayTreeNode* A, SplayTreeNode* B); + std::pair Split(int key); + + ~SplayTreeNode(); + }; + + SplayTreeNode* root = nullptr; + SplayTree(SplayTreeNode*); + + public: + SplayTree() = default; + SplayTree(SplayTree const& other) = delete; + SplayTree(SplayTree&& old); + + void Insert(int key, int value); + int SearchExact(int key); + std::pair SearchMinGTQ(int key); + std::pair SearchMaxLEQ(int key); + std::pair SearchMin(); + std::pair SearchMax(); + void Delete(int key); + std::pair Split(int key); + void Merge(SplayTree&& other); + + ~SplayTree(); +}; diff --git a/task_08/src/hashtable.cpp b/task_08/src/hashtable.cpp new file mode 100644 index 0000000..0d43e8a --- /dev/null +++ b/task_08/src/hashtable.cpp @@ -0,0 +1,67 @@ +#include "hashtable.hpp" + +#include +#include + +Hashmap::Hashmap(int default_value) + : size(0), + cap(8), + scale(3), + step_b(13), + default_value(default_value), + buzy(cap), + deleted(cap), + data(cap) {} + +void Hashmap::Double() { + cap *= 2; + size = 0; + + std::random_device dev; + + scale = dev() & (cap - 1) | 1; + step_b = dev() & (cap - 1) | 1; + + std::vector new_data(cap); + std::vector new_buzy(cap); + std::vector new_deleted(cap); + + for (uint i = 0; i < cap / 2; ++i) { + if (!buzy[i]) continue; + + auto entry = data[i]; + int h = Hash(entry.k); + while (new_buzy[h]) h = Step(h); + + new_data[h] = entry; + new_buzy[h] = true; + ++size; + } + + data = std::move(new_data); + buzy = std::move(new_buzy); + deleted = std::move(new_deleted); +} + +int& Hashmap::operator[](int k) { + if (size * 2 > cap) Double(); + + int h = Hash(k); + while (deleted[h] || (buzy[h] && data[h].k != k)) h = Step(h); + + if (!buzy[h]) { + data[h].k = k; + data[h].v = default_value; + buzy[h] = true; + size += 1; + } + + return data[h].v; +} + +void Hashmap::Erase(int k) { + int h = Hash(k); + while (deleted[h] || (buzy[h] && data[h].k != k)) h = Step(h); + + if (buzy[h]) deleted[h] = true; +} diff --git a/task_08/src/hashtable.hpp b/task_08/src/hashtable.hpp new file mode 100644 index 0000000..fbcd3fe --- /dev/null +++ b/task_08/src/hashtable.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +class Hashmap { + private: + struct Entry { + int k; + int v; + }; + int size; + int cap; + int scale; + const int step_a = 25; + int step_b; + const int default_value; + std::vector buzy; + std::vector deleted; + std::vector data; + + void Double(); + unsigned int Hash(unsigned int k) { return (scale * k) % cap; } + unsigned int Step(unsigned int k) { return (step_a * k + step_b) % cap; } + + public: + Hashmap(int default_value = 0); + int& operator[](int k); + void Erase(int k); +}; diff --git a/task_08/src/test.cpp b/task_08/src/test.cpp index 5e11617..0047a4c 100644 --- a/task_08/src/test.cpp +++ b/task_08/src/test.cpp @@ -1,6 +1,145 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "hashtable.hpp" + +TEST(Hashtable, Simple) { + Hashmap map; + + map[0] = 0; + + ASSERT_EQ(map[0], 0); + + map[1] = 1; + map[2] = 2; + + ASSERT_EQ(map[1], 1); + ASSERT_EQ(map[2], 2); +} + +TEST(Hashtable, SimpleOverwrite) { + Hashmap map; + + map[0] = 0; + + ASSERT_EQ(map[0], 0); + + map[1] = 1; + map[2] = 2; + + ASSERT_EQ(map[1], 1); + ASSERT_EQ(map[2], 2); + + map[0] = -1; + + ASSERT_EQ(map[0], -1); + + map[1] = -2; + map[2] = -3; + + ASSERT_EQ(map[1], -2); + ASSERT_EQ(map[2], -3); +} + +TEST(Hashtable, SimpleNegative) { + Hashmap map; + + map[-15] = -15; + + ASSERT_EQ(map[-15], -15); +} + +TEST(Hashtable, Longer) { + Hashmap map; + + for (uint i = 0; i < 100; ++i) map[i] = i; + + for (uint i = 0; i < 100; ++i) ASSERT_EQ(map[i], i) << "Wrong at i=" << i; +} + +TEST(Hashtable, SimpleErase) { + Hashmap map; + + map[0] = 0; + map[1] = 1; + map[2] = 2; + + ASSERT_EQ(map[2], 2); + + map.Erase(2); + + ASSERT_EQ(map[2], 0); +} + +TEST(Hashtable, EraseDefaultValue) { + Hashmap map(13); + + map[0] = 0; + + ASSERT_EQ(map[0], 0); + + map[1] = 1; + map[2] = 2; + + ASSERT_EQ(map[1], 1); + ASSERT_EQ(map[2], 2); + + map.Erase(2); + + ASSERT_EQ(map[2], 13); +} + +TEST(Hashtable, RandomDense) { + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist(-100, 100); + + Hashmap map; + std::vector samples; + + for (uint i = 0; i < 100000; ++i) { + int val = dist(rng); + map[i] = val; + samples.push_back(val); + } + for (uint i = 0; i < 100000; ++i) + ASSERT_EQ(map[i], samples[i]) << "wrong value at i=" << i; +} + +TEST(Hashtable, RandomSparce) { + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist(-1000000, 1000000); + + Hashmap map; + std::vector samples; + + for (uint i = 0; i < 100000; ++i) { + int val = dist(rng); + map[i] = val; + samples.push_back(val); + } + for (uint i = 0; i < 100000; ++i) + ASSERT_EQ(map[i], samples[i]) << "wrong value at i=" << i; +} + +TEST(Hashtable, RandomRandom) { + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist(-1000000, 1000000); + std::uniform_int_distribution dist_sample(0, 10000 - 1); + + Hashmap map; + std::vector samples(10000); + + for (uint i = 0; i < 100000; ++i) { + int val = dist(rng); + int sample = dist_sample(rng); + map[sample] = val; + samples[sample] = (val); + } + for (uint i = 0; i < 10000; ++i) + ASSERT_EQ(map[i], samples[i]) << "wrong value at i=" << i; } From 43f4ab958972816e158d4c092225ae52e3fbed6a Mon Sep 17 00:00:00 2001 From: Ivan-Voronyuk Date: Mon, 23 Jun 2025 06:42:00 +0300 Subject: [PATCH 2/2] Fixed first task Fixed first task random test fail --- task_01/src/solution.cpp | 12 ++++++------ task_01/src/test.cpp | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/task_01/src/solution.cpp b/task_01/src/solution.cpp index 784699d..02a66f0 100644 --- a/task_01/src/solution.cpp +++ b/task_01/src/solution.cpp @@ -8,11 +8,11 @@ int BinarySearchGEQ(const std::vector& arr, int target, int left, int right) { while (left < right) { - int mid = left + (right - left + 1) / 2; - if (arr[mid] > target) { - right = mid - 1; + int mid = left + (right - left) / 2; + if (arr[mid] < target) { + left = mid + 1; } else { - left = mid; + right = mid; } } return left; @@ -31,10 +31,10 @@ std::pair FindPairMatchSum(const std::vector& arr, int target) { unsigned int left = 0; unsigned int right = BinarySearchGEQ(arr, target - arr[left], 0, arr.size() - 1); - while (left < arr.size() - 1 && arr[left] + arr[left + 1] < target) { + while (left < arr.size() - 1 && arr[left] + arr[left + 1] <= target) { if (arr[left] + arr[right] == target) return {arr[left], arr[right]}; left += 1; right = BinarySearchGEQ(arr, target - arr[left], left, right); } - throw std::runtime_error("Failed to find sutable pair"); + throw std::runtime_error("Failed to find suiable pair"); } diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index c7ebc85..0f1a9ed 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -16,20 +16,52 @@ TEST(BinarySearchSubtest, MiddleCases) { } TEST(BinarySearchSubtest, Inequality) { ASSERT_EQ(BinarySearchGEQ({0, 2, 4, 6, 8, 9}, 31, 0, 5), 5); // Stack [] - ASSERT_EQ(BinarySearchGEQ({0, 2, 3, 6, 7, 9}, 5, 0, 5), 2); // Stack [] + ASSERT_EQ(BinarySearchGEQ({0, 2, 3, 6, 7, 9}, 5, 0, 5), 3); // Stack [] ASSERT_EQ(BinarySearchGEQ({1, 2, 3, 6, 7, 9}, 0, 0, 5), 0); // Stack [] } +TEST(BinarySearchSubtest, Randomx100) { + std::vector arr(100); + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist_gen(0, 1000); + std::uniform_int_distribution dist_sample(0, arr.size() - 1); + + for (int repetion = 0; repetion < 10000; ++repetion) { + for (int j = 0; j < arr.size(); ++j) arr[j] = dist_gen(rng); + std::sort(arr.begin(), arr.end()); + + int sample = dist_gen(rng); + int res_pos = BinarySearchGEQ(arr, sample, 0, arr.size() - 1); + + if (res_pos != arr.size() - 1) ASSERT_GE(arr[res_pos], sample); + if (res_pos > 0) ASSERT_LT(arr[res_pos - 1], sample); + } +} + +TEST(SolutionTest, Simple) { + { + auto [L, R] = FindPairMatchSum({1, 2, 3, 4, 8, 8, 8, 8, 9}, 13); + ASSERT_EQ(L, 4); + ASSERT_EQ(R, 9); + } + + { + auto [L, R] = FindPairMatchSum({1, 1, 1, 4, 8, 8, 8, 8, 9, 10, 11}, 13); + ASSERT_EQ(L, 4); + ASSERT_EQ(R, 9); + } +} TEST(SolutionTest, Random100of1000x1000) { std::vector arr(100); std::random_device dev; std::mt19937 rng(dev()); std::uniform_int_distribution dist_gen(0, 1000); - std::uniform_int_distribution dist_sample(0, 99); + std::uniform_int_distribution dist_sample(0, arr.size() - 1); for (int i = 0; i < 1000; ++i) { // gen - for (int i = 0; i < 100; ++i) arr[i] = dist_gen(rng); + for (int j = 0; j < 100; ++j) arr[j] = dist_gen(rng); // sort array according to task std::sort(arr.begin(), arr.end());