diff --git a/task_01/src/task_01.cpp b/task_01/src/task_01.cpp new file mode 100644 index 0000000..f9154da --- /dev/null +++ b/task_01/src/task_01.cpp @@ -0,0 +1,17 @@ +#include "task_01.hpp" + +std::vector FindTwoNums(int target, const std::vector& arr) { + int left = 0; + int right = arr.size() - 1; + while (left < right) { + int sum = arr[left] + arr[right]; + if (sum == target) { + return {arr[left], arr[right]}; + } else if (sum < target) { + ++left; + } else { + --right; + } + } + return {}; +}; \ No newline at end of file diff --git a/task_01/src/task_01.hpp b/task_01/src/task_01.hpp new file mode 100644 index 0000000..13aefe2 --- /dev/null +++ b/task_01/src/task_01.hpp @@ -0,0 +1,4 @@ +#pragma once +#include + +std::vector FindTwoNums(int target, const std::vector& arr); \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..cf3c90f 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,39 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include +#include + +#include "task_01.hpp" + +TEST(FindTwoNumsTest, BasicMatch) { + std::vector arr = {1, 2, 3, 4, 6}; + auto result = FindTwoNums(7, arr); + std::sort(result.begin(), result.end()); + ASSERT_EQ(result, std::vector({1, 6})); +} + +TEST(FindTwoNumsTest, MultiplePairsPossible) { + std::vector arr = {1, 2, 3, 4, 4, 5}; + auto result = FindTwoNums(8, arr); + ASSERT_EQ(result[0] + result[1], 8); +} + +TEST(FindTwoNumsTest, NoSolution) { + std::vector arr = {1, 2, 3}; + ASSERT_EQ(FindTwoNums(10, arr), std::vector{}); +} + +TEST(FindTwoNumsTest, NegativeNumbers) { + std::vector arr = {-5, -2, 0, 3, 7, 9}; + auto result = FindTwoNums(4, arr); + std::sort(result.begin(), result.end()); + ASSERT_EQ(result, std::vector({-5, 9})); +} + +TEST(FindTwoNumsTest, SameElementTwice) { + std::vector arr = {1, 2, 4, 4, 5, 6}; + auto result = FindTwoNums(8, arr); + std::sort(result.begin(), result.end()); + ASSERT_EQ(result, std::vector({2, 6})); } \ No newline at end of file diff --git a/task_02/src/stack.cpp b/task_02/src/stack.cpp deleted file mode 100644 index 8ca8990..0000000 --- a/task_02/src/stack.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "stack.hpp" - -#include - -void Stack::Push(int value) { data_.push(value); } - -int Stack::Pop() { - auto result = data_.top(); - data_.pop(); - return result; -} - -void MinStack::Push(int value) { data_.push_back(value); } - -int MinStack::Pop() { - auto result = data_.back(); - data_.pop_back(); - return result; -} - -int MinStack::GetMin() { return *std::min_element(data_.begin(), data_.end()); } \ No newline at end of file diff --git a/task_02/src/stack.hpp b/task_02/src/stack.hpp index 138ec40..0377dc0 100644 --- a/task_02/src/stack.hpp +++ b/task_02/src/stack.hpp @@ -1,23 +1,117 @@ #pragma once -#include +#include #include +template class Stack { public: - void Push(int value); - int Pop(); + Stack(){}; + Stack(std::vector vec) { + for (auto val : vec) { + push(val); + } + } + void Push(T value) { data_.push_back(value); } + T Pop() { + if (data_.empty()) { + throw std::runtime_error("Stack is empty."); + } + T result = data_.back(); + data_.pop_back(); + return result; + } + + int Size() { return data_.size(); } + + bool IsEmpty() { return data_.empty(); } private: - std::stack data_; + std::vector data_; }; +template class MinStack { public: - void Push(int value); - int Pop(); - int GetMin(); + MinStack(){}; + MinStack(std::vector vec) { + for (auto val : vec) { + push(val); + } + } + void Push(T value) { + data_.push_back(value); + if (data_mins_.size() == 0 || value <= data_mins_.back()) { + data_mins_.push_back(value); + } else { + data_mins_.push_back(data_mins_.back()); + } + } + T Pop() { + if (data_.empty()) { + throw std::runtime_error("Stack is empty."); + } + T result = data_.back(); + data_.pop_back(); + data_mins_.pop_back(); + return result; + } + + T GetMin() { + if (data_mins_.size() == 0) { + throw std::runtime_error("Пустой стек - нет минимума"); + } + return data_mins_.back(); + } + + int Size() { return data_.size(); } + + bool IsEmpty() { return data_.empty(); } private: - std::vector data_; + std::vector data_; + std::vector data_mins_; }; + +template +class MaxStack { + public: + MaxStack(){}; + MaxStack(std::vector vec) { + for (auto val : vec) { + push(val); + } + } + void Push(T value) { + data_.push_back(value); + if (data_maxs.size() == 0 || value >= data_maxs.back()) { + data_maxs.push_back(value); + } else { + data_maxs.push_back(data_maxs.back()); + } + } + T Pop() { + if (data_.empty()) { + throw std::runtime_error("Stack is empty."); + } + T result = data_.back(); + data_.pop_back(); + data_maxs.pop_back(); + return result; + } + + T GetMax() { + if (data_maxs.size() == 0) { + throw std::runtime_error("Пустой стек - нет минимума"); + } + return data_maxs.back(); + } + + int Size() { return data_.size(); } + + bool IsEmpty() { return data_.empty(); } + + private: + std::vector data_; + std::vector data_maxs; +}; \ No newline at end of file diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 54e7ce9..d6f4bd8 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -6,7 +6,7 @@ #include "stack.hpp" TEST(StackTest, Simple) { - Stack stack; + Stack stack; stack.Push(1); // Stack [1] ASSERT_EQ(stack.Pop(), 1); // Stack [] stack.Push(1); // Stack [1] @@ -22,7 +22,7 @@ TEST(StackTest, Simple) { } TEST(MinStackTest, Simple) { - MinStack stack; + MinStack stack; stack.Push(1); // Stack [1] ASSERT_EQ(stack.GetMin(), 1); ASSERT_EQ(stack.Pop(), 1); // Stack [] @@ -39,4 +39,111 @@ TEST(MinStackTest, Simple) { ASSERT_EQ(stack.GetMin(), 1); ASSERT_EQ(stack.Pop(), 3); // Stack [1] ASSERT_EQ(stack.Pop(), 1); // Stack [] +} + +// ------------------------- Stack ---------------------------- + +TEST(StackTest, BasicPushPop) { + Stack s; + s.Push(1); + s.Push(2); + EXPECT_EQ(s.Pop(), 2); + EXPECT_EQ(s.Pop(), 1); +} + +TEST(StackTest, IsEmptyInitially) { + Stack s; + EXPECT_TRUE(s.IsEmpty()); + EXPECT_EQ(s.Size(), 0); +} + +TEST(StackTest, SizeIncreasesAndDecreases) { + Stack s; + s.Push(1); + s.Push(2); + EXPECT_EQ(s.Size(), 2); + s.Pop(); + EXPECT_EQ(s.Size(), 1); +} + +TEST(StackTest, PopFromEmptyStackThrows) { + Stack s; + EXPECT_THROW(s.Pop(), std::runtime_error); +} + +// ------------------------- MinStack ---------------------------- + +TEST(MinStackTest, GetMinBasic) { + MinStack s; + s.Push(5); + s.Push(3); + s.Push(7); + EXPECT_EQ(s.GetMin(), 3); + s.Pop(); // pop 7 + EXPECT_EQ(s.GetMin(), 3); + s.Pop(); // pop 3 + EXPECT_EQ(s.GetMin(), 5); +} + +TEST(MinStackTest, IsEmptyInitially) { + MinStack s; + EXPECT_TRUE(s.IsEmpty()); + EXPECT_EQ(s.Size(), 0); +} + +TEST(MinStackTest, SizeWorksCorrectly) { + MinStack s; + s.Push(10); + s.Push(20); + EXPECT_EQ(s.Size(), 2); + s.Pop(); + EXPECT_EQ(s.Size(), 1); +} + +TEST(MinStackTest, PopFromEmptyStackThrows) { + MinStack s; + EXPECT_THROW(s.Pop(), std::runtime_error); +} + +TEST(MinStackTest, GetMinFromEmptyThrows) { + MinStack s; + EXPECT_THROW(s.GetMin(), std::runtime_error); +} + +// ------------------------- MaxStack ---------------------------- + +TEST(MaxStackTest, GetMaxBasic) { + MaxStack s; + s.Push(1); + s.Push(3); + s.Push(2); + EXPECT_EQ(s.GetMax(), 3); + s.Pop(); // pop 2 + EXPECT_EQ(s.GetMax(), 3); + s.Pop(); // pop 3 + EXPECT_EQ(s.GetMax(), 1); +} + +TEST(MaxStackTest, IsEmptyInitially) { + MaxStack s; + EXPECT_TRUE(s.IsEmpty()); +} + +TEST(MaxStackTest, PopFromEmptyThrows) { + MaxStack s; + EXPECT_THROW(s.Pop(), std::runtime_error); +} + +TEST(MaxStackTest, GetMaxFromEmptyThrows) { + MaxStack s; + EXPECT_THROW(s.GetMax(), std::runtime_error); +} + +TEST(MaxStackTest, SizeWorksCorrectly) { + MaxStack s; + EXPECT_EQ(s.Size(), 0); + s.Push(42); + EXPECT_EQ(s.Size(), 1); + s.Pop(); + EXPECT_EQ(s.Size(), 0); } \ No newline at end of file diff --git a/task_03/src/days_untill_warmer.cpp b/task_03/src/days_untill_warmer.cpp new file mode 100644 index 0000000..49e4b44 --- /dev/null +++ b/task_03/src/days_untill_warmer.cpp @@ -0,0 +1,23 @@ +#include "days_untill_warmer.hpp" + +#include + +std::vector DaysUntilWarmer(const std::vector& temperatures) { + int n = temperatures.size(); + if (n == 0) { + throw std::runtime_error("Empty array"); + } + std::vector result(n, 0); + std::stack st; + + for (int i = 0; i < n; ++i) { + while (!st.empty() && temperatures[i] > temperatures[st.top()]) { + int prev_index = st.top(); + st.pop(); + result[prev_index] = i - prev_index; + } + st.push(i); + } + + return result; +} diff --git a/task_03/src/days_untill_warmer.hpp b/task_03/src/days_untill_warmer.hpp new file mode 100644 index 0000000..4b06535 --- /dev/null +++ b/task_03/src/days_untill_warmer.hpp @@ -0,0 +1,5 @@ +#pragma once +#include +#include + +std::vector DaysUntilWarmer(const std::vector& temperatures); diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..34275c9 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,53 @@ #include -#include "topology_sort.hpp" +#include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "days_untill_warmer.hpp" + +TEST(DaysUntilWarmerTest, IncreasingTemperatures) { + std::vector temps = {10, 20, 30, 40}; + std::vector expected = {1, 1, 1, 0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, DecreasingTemperatures) { + std::vector temps = {40, 30, 20, 10}; + std::vector expected = {0, 0, 0, 0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, MixedTemperatures) { + std::vector temps = {30, 40, 35, 42, 38, 33, 50}; + std::vector expected = {1, 2, 1, 3, 2, 1, 0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, AllSameTemperatures) { + std::vector temps = {25, 25, 25, 25}; + std::vector expected = {0, 0, 0, 0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, OneDayOnly) { + std::vector temps = {31}; + std::vector expected = {0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, SpikeAtTheEnd) { + std::vector temps = {30, 25, 20, 35}; + std::vector expected = {3, 2, 1, 0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, ValleyInMiddle) { + std::vector temps = {45, 30, 35, 20, 50}; + std::vector expected = {4, 1, 2, 1, 0}; + EXPECT_EQ(DaysUntilWarmer(temps), expected); +} + +TEST(DaysUntilWarmerTest, Empty) { + std::vector temps = {}; + EXPECT_THROW(DaysUntilWarmer(temps), std::runtime_error); } 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/buy_fish.cpp b/task_04/src/buy_fish.cpp new file mode 100644 index 0000000..5b0cf5d --- /dev/null +++ b/task_04/src/buy_fish.cpp @@ -0,0 +1,24 @@ +#include "buy_fish.hpp" + +std::vector buy_fish(const std::vector& prices, int k) { + int N = prices.size(); + std::vector result(N, 0); + std::deque dq; + + for (int i = 0; i < N; ++i) { + while (!dq.empty() && dq.front() < i - k + 1) { + dq.pop_front(); + } + + while (!dq.empty() && prices[dq.back()] >= prices[i]) { + dq.pop_back(); + } + + dq.push_back(i); + + int bestDay = dq.front(); + result[bestDay]++; + } + + return result; +} diff --git a/task_04/src/buy_fish.hpp b/task_04/src/buy_fish.hpp new file mode 100644 index 0000000..8e153b6 --- /dev/null +++ b/task_04/src/buy_fish.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +std::vector buy_fish(const std::vector& prices, int k); \ No newline at end of file diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..dde9535 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,86 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "buy_fish.hpp" + +namespace { + +int totalFishBought(const std::vector& purchases) { + int total = 0; + for (int p : purchases) total += p; + return total; +} + +bool isValidSchedule(const std::vector& purchases, int k) { + int n = purchases.size(); + std::vector stock(n + k, 0); + for (int i = 0; i < n; ++i) { + for (int j = i; j < std::min(i + k, n); ++j) { + stock[j] += purchases[i]; + } + } + for (int i = 0; i < n; ++i) { + if (stock[i] == 0) return false; + stock[i]--; + } + return true; +} + +} // namespace + +TEST(BuyFishTest, SimpleIncreasingPrices) { + std::vector prices = {1, 2, 3, 4, 5}; + int k = 2; + auto result = buy_fish(prices, k); + EXPECT_EQ(result.size(), prices.size()); + EXPECT_EQ(totalFishBought(result), prices.size()); + EXPECT_TRUE(isValidSchedule(result, k)); +} + +TEST(BuyFishTest, SimpleDecreasingPrices) { + std::vector prices = {5, 4, 3, 2, 1}; + int k = 3; + auto result = buy_fish(prices, k); + EXPECT_EQ(result.size(), prices.size()); + EXPECT_EQ(totalFishBought(result), prices.size()); + EXPECT_TRUE(isValidSchedule(result, k)); +} + +TEST(BuyFishTest, ConstantPrices) { + std::vector prices = {10, 10, 10, 10, 10}; + int k = 2; + auto result = buy_fish(prices, k); + EXPECT_EQ(result.size(), prices.size()); + EXPECT_EQ(totalFishBought(result), prices.size()); + EXPECT_TRUE(isValidSchedule(result, k)); +} + +TEST(BuyFishTest, OneDayShelfLife) { + std::vector prices = {3, 2, 4, 1, 5}; + int k = 1; + auto result = buy_fish(prices, k); + EXPECT_EQ(result.size(), prices.size()); + EXPECT_EQ(totalFishBought(result), prices.size()); + EXPECT_TRUE(isValidSchedule(result, k)); +} + +TEST(BuyFishTest, LargeKLongPlanning) { + std::vector prices = {9, 1, 2, 3, 4, 1, 10, 2, 3, 4}; + int k = 5; + auto result = buy_fish(prices, k); + EXPECT_EQ(result.size(), prices.size()); + EXPECT_EQ(totalFishBought(result), prices.size()); + EXPECT_TRUE(isValidSchedule(result, k)); +} + +TEST(BuyFishTest, AlwaysBuyOnePerDay) { + std::vector prices = {5, 4, 6, 7, 3}; + int k = 1; + auto result = buy_fish(prices, k); + EXPECT_EQ(result.size(), prices.size()); + for (int r : result) { + EXPECT_EQ(r, 1); // можно купить только на сегодня + } } diff --git a/task_05/src/QuickSort.cpp b/task_05/src/QuickSort.cpp new file mode 100644 index 0000000..9ac0b08 --- /dev/null +++ b/task_05/src/QuickSort.cpp @@ -0,0 +1,28 @@ +#include "QuickSort.hpp" + +namespace { +void quickSortwrap(std::vector& arr, int low, int high) { + if (low < high) { + int pivot = arr[high]; + int i = low - 1; + + for (int j = low; j < high; j++) { + if (arr[j] < pivot) { + i++; + std::swap(arr[i], arr[j]); + } + } + std::swap(arr[i + 1], arr[high]); + int pi = i + 1; + + quickSortwrap(arr, low, pi - 1); + quickSortwrap(arr, pi + 1, high); + } +}; +} // namespace + +void quickSort(std::vector& arr) { + if (!arr.empty()) { + quickSortwrap(arr, 0, arr.size() - 1); + } +}; \ No newline at end of file diff --git a/task_05/src/QuickSort.hpp b/task_05/src/QuickSort.hpp new file mode 100644 index 0000000..b6c92b9 --- /dev/null +++ b/task_05/src/QuickSort.hpp @@ -0,0 +1,4 @@ +#pragma once +#include + +void quickSort(std::vector& arr); \ No newline at end of file diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..40689ef 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,79 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include + +#include "QuickSort.hpp" + +namespace { +bool isSorted(const std::vector& arr) { + return std::is_sorted(arr.begin(), arr.end()); +} +} // namespace + +TEST(QuickSortTest, AlreadySorted) { + std::vector arr = {1, 2, 3, 4, 5}; + quickSort(arr); + EXPECT_TRUE(isSorted(arr)); +} + +TEST(QuickSortTest, ReverseSorted) { + std::vector arr = {5, 4, 3, 2, 1}; + quickSort(arr); + EXPECT_TRUE(isSorted(arr)); +} + +TEST(QuickSortTest, RandomOrder) { + std::vector arr = {3, 1, 4, 1, 5, 9, 2}; + quickSort(arr); + EXPECT_TRUE(isSorted(arr)); +} + +TEST(QuickSortTest, EmptyArray) { + std::vector arr; + quickSort(arr); + EXPECT_TRUE(arr.empty()); +} + +TEST(QuickSortTest, SingleElement) { + std::vector arr = {42}; + quickSort(arr); + EXPECT_EQ(arr, std::vector({42})); +} + +TEST(QuickSortTest, TwoElementsSorted) { + std::vector arr = {1, 2}; + quickSort(arr); + EXPECT_EQ(arr, std::vector({1, 2})); +} + +TEST(QuickSortTest, TwoElementsUnsorted) { + std::vector arr = {2, 1}; + quickSort(arr); + EXPECT_EQ(arr, std::vector({1, 2})); +} + +TEST(QuickSortTest, AllEqualElements) { + std::vector arr = {7, 7, 7, 7, 7}; + quickSort(arr); + EXPECT_EQ(arr, std::vector({7, 7, 7, 7, 7})); +} + +TEST(QuickSortTest, ContainsNegatives) { + std::vector arr = {-3, -1, -4, -2, 0}; + quickSort(arr); + EXPECT_TRUE(isSorted(arr)); +} + +TEST(QuickSortTest, DuplicatesAndUnique) { + std::vector arr = {4, 1, 3, 4, 2, 4, 5}; + quickSort(arr); + EXPECT_TRUE(isSorted(arr)); +} + +TEST(QuickSortTest, LargeInput) { + std::vector arr(1000); + for (int i = 0; i < 1000; ++i) arr[i] = rand() % 10000; + quickSort(arr); + EXPECT_TRUE(isSorted(arr)); } diff --git a/task_06/src/ord_stat.cpp b/task_06/src/ord_stat.cpp new file mode 100644 index 0000000..746be01 --- /dev/null +++ b/task_06/src/ord_stat.cpp @@ -0,0 +1,30 @@ +#include "ord_stat.hpp" + +int ordstat(std::vector& arr, int k) { + int left = 0; + int right = arr.size() - 1; + + while (left <= right) { + int pivot_index = left + rand() % (right - left + 1); + int pivotValue = arr[pivot_index]; + std::swap(arr[pivot_index], arr[right]); + + int storeIndex = left; + for (int i = left; i < right; i++) { + if (arr[i] <= pivotValue) { + std::swap(arr[i], arr[storeIndex]); + storeIndex++; + } + } + std::swap(arr[storeIndex], arr[right]); + + if (storeIndex == k) + return arr[storeIndex]; + else if (storeIndex < k) + left = storeIndex + 1; + else + right = storeIndex - 1; + } + + return -1; +} \ No newline at end of file diff --git a/task_06/src/ord_stat.hpp b/task_06/src/ord_stat.hpp new file mode 100644 index 0000000..3ddab27 --- /dev/null +++ b/task_06/src/ord_stat.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +int ordstat(std::vector& arr, int k); \ No newline at end of file diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..1c11790 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,56 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include + +#include "ord_stat.hpp" + +TEST(OrdStatTest, MinimumElement) { + std::vector arr = {4, 2, 5, 1, 3}; + EXPECT_EQ(ordstat(arr, 0), 1); +} + +TEST(OrdStatTest, MaximumElement) { + std::vector arr = {7, 8, 2, 5, 9}; + EXPECT_EQ(ordstat(arr, arr.size() - 1), 9); +} + +TEST(OrdStatTest, MedianElementOdd) { + std::vector arr = {5, 1, 9, 3, 7}; + EXPECT_EQ(ordstat(arr, 2), 5); +} + +TEST(OrdStatTest, MedianElementEven) { + std::vector arr = {10, 20, 30, 40}; + int result = ordstat(arr, 1); + EXPECT_EQ(result, 20); } + +TEST(OrdStatTest, AllEqualElements) { + std::vector arr = {6, 6, 6, 6, 6}; + EXPECT_EQ(ordstat(arr, 3), 6); +} + +TEST(OrdStatTest, ContainsNegatives) { + std::vector arr = {-5, -10, 0, 5, 10}; + EXPECT_EQ(ordstat(arr, 1), -5); + EXPECT_EQ(ordstat(arr, 4), 10); +} + +TEST(OrdStatTest, DuplicatesInArray) { + std::vector arr = {4, 1, 4, 2, 2, 3}; + EXPECT_EQ(ordstat(arr, 3), 3); +} + +TEST(OrdStatTest, SingleElement) { + std::vector arr = {99}; + EXPECT_EQ(ordstat(arr, 0), 99); +} + +TEST(OrdStatTest, LargeArrayRandom) { + std::vector arr(1000); + for (int i = 0; i < 1000; ++i) arr[i] = rand() % 10000; + std::vector sorted = arr; + std::sort(sorted.begin(), sorted.end()); + EXPECT_EQ(ordstat(arr, 500), sorted[500]); +} \ No newline at end of file diff --git a/task_07/src/AVLTree.hpp b/task_07/src/AVLTree.hpp new file mode 100644 index 0000000..a162734 --- /dev/null +++ b/task_07/src/AVLTree.hpp @@ -0,0 +1,153 @@ +#pragma once + +#include + +class AVLTree { + private: + struct Node { + int key; + Node* left{nullptr}; + Node* right{nullptr}; + int height; + Node(int k) : key(k), left(nullptr), right(nullptr), height(1) {} + ~Node() { + delete left; + delete right; + } + }; + + Node* root = nullptr; + + int height(Node* n) { return n ? n->height : 0; } + + int balanceFactor(Node* n) { + return n ? height(n->left) - height(n->right) : 0; + } + + void updateHeight(Node* n) { + n->height = 1 + std::max(height(n->left), height(n->right)); + } + + Node* rotateRight(Node* y) { + Node* x = y->left; + Node* T2 = x->right; + + x->right = y; + y->left = T2; + + updateHeight(y); + updateHeight(x); + + return x; + } + + Node* rotateLeft(Node* x) { + Node* y = x->right; + Node* T2 = y->left; + + y->left = x; + x->right = T2; + + updateHeight(x); + updateHeight(y); + + return y; + } + + Node* balance(Node* n) { + updateHeight(n); + int bf = balanceFactor(n); + + if (bf > 1) { + if (balanceFactor(n->left) < 0) { + n->left = rotateLeft(n->left); + } + return rotateRight(n); + } + + if (bf < -1) { + if (balanceFactor(n->right) > 0) { + n->right = rotateRight(n->right); + } + return rotateLeft(n); + } + + return n; + } + + Node* insert(Node* node, int key) { + if (!node) return new Node(key); + + if (key < node->key) + node->left = insert(node->left, key); + else if (key > node->key) + node->right = insert(node->right, key); + else + return node; + + return balance(node); + } + + Node* minValueNode(Node* node) { + Node* current = node; + while (current->left) current = current->left; + return current; + } + + Node* erase(Node* node, int key) { + if (!node) return node; + + if (key < node->key) + node->left = erase(node->left, key); + else if (key > node->key) + node->right = erase(node->right, key); + else { + if (!node->left || !node->right) { + Node* temp = node->left ? node->left : node->right; + if (!temp) { + temp = node; + node = nullptr; + } else { + *node = *temp; + } + delete temp; + } else { + Node* temp = minValueNode(node->right); + node->key = temp->key; + node->right = erase(node->right, temp->key); + } + } + + if (!node) return node; + + return balance(node); + } + + bool find(Node* node, int key) const { + if (!node) return false; + if (key == node->key) return true; + if (key < node->key) + return find(node->left, key); + else + return find(node->right, key); + } + + void inorder(Node* node) const { + if (!node) return; + inorder(node->left); + std::cout << node->key << " "; + inorder(node->right); + } + + public: + void insert(int key) { root = insert(root, key); } + + void erase(int key) { root = erase(root, key); } + + bool find(int key) const { return find(root, key); } + + void printInorder() const { + inorder(root); + std::cout << "\n"; + } +}; diff --git a/task_07/src/test.cpp b/task_07/src/test.cpp index 5e11617..e335245 100644 --- a/task_07/src/test.cpp +++ b/task_07/src/test.cpp @@ -1,6 +1,80 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include +#include + +#include "AVLTree.hpp" + +class AVLTreeTest : public ::testing::Test { + protected: + AVLTree tree; + + void collectInorder(std::vector& out) {} +}; + +TEST_F(AVLTreeTest, InsertAndFind) { + tree.insert(10); + tree.insert(20); + tree.insert(5); + + EXPECT_TRUE(tree.find(10)); + EXPECT_TRUE(tree.find(20)); + EXPECT_TRUE(tree.find(5)); + EXPECT_FALSE(tree.find(15)); +} + +TEST_F(AVLTreeTest, InsertDuplicates) { + tree.insert(10); + tree.insert(10); + tree.insert(10); + + EXPECT_TRUE(tree.find(10)); +} + +TEST_F(AVLTreeTest, EraseLeaf) { + tree.insert(10); + tree.insert(5); + tree.insert(15); + tree.erase(5); + + EXPECT_FALSE(tree.find(5)); + EXPECT_TRUE(tree.find(10)); + EXPECT_TRUE(tree.find(15)); +} + +TEST_F(AVLTreeTest, EraseNodeWithOneChild) { + tree.insert(10); + tree.insert(5); + tree.insert(7); + tree.erase(5); + + EXPECT_FALSE(tree.find(5)); + EXPECT_TRUE(tree.find(7)); + EXPECT_TRUE(tree.find(10)); +} + +TEST_F(AVLTreeTest, EraseNodeWithTwoChildren) { + tree.insert(10); + tree.insert(5); + tree.insert(15); + tree.insert(12); + tree.insert(18); + tree.erase(15); + + EXPECT_FALSE(tree.find(15)); + EXPECT_TRUE(tree.find(12)); + EXPECT_TRUE(tree.find(18)); + EXPECT_TRUE(tree.find(10)); +} + +TEST_F(AVLTreeTest, BalanceProperty) { + for (int i = 1; i <= 1000; ++i) { + tree.insert(i); + } + + for (int i = 1; i <= 1000; ++i) { + EXPECT_TRUE(tree.find(i)); + } } diff --git a/task_08/src/HashTable.hpp b/task_08/src/HashTable.hpp new file mode 100644 index 0000000..bed494c --- /dev/null +++ b/task_08/src/HashTable.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include +#include +#include + +template +class HashTable { + private: + std::vector>> table; + int capacity; + int size; + + int getIndex(const std::string& key) const { + return std::hash{}(key) % capacity; + } + + void rehash() { + int old_capacity = capacity; + capacity *= 2; + std::vector>> new_table(capacity); + + for (const auto& bucket : table) { + for (const auto& entry : bucket) { + int idx = std::hash{}(entry.first) % capacity; + new_table[idx].emplace_back(entry.first, entry.second); + } + } + + table = std::move(new_table); + } + + void checkLoadFactorAndRehash() { + if (size > capacity / 2) { + rehash(); + } + } + + public: + HashTable(int init_capacity = 8) : capacity(init_capacity), size(0) { + table.resize(capacity); + } + + void insert(const std::string& key, T value) { + int idx = getIndex(key); + for (auto& entry : table[idx]) { + if (entry.first == key) { + entry.second = value; + return; + } + } + table[idx].emplace_back(key, value); + ++size; + checkLoadFactorAndRehash(); + } + + std::optional find(const std::string& key) const { + int idx = getIndex(key); + for (const auto& entry : table[idx]) { + if (entry.first == key) { + return entry.second; + } + } + return std::nullopt; + } + + bool erase(const std::string& key) { + int idx = getIndex(key); + for (auto it = table[idx].begin(); it != table[idx].end(); ++it) { + if (it->first == key) { + table[idx].erase(it); + --size; + return true; + } + } + return false; + } + + void print() const { + for (int i = 0; i < capacity; ++i) { + std::cout << "[" << i << "]: "; + for (const auto& entry : table[i]) { + std::cout << "(" << entry.first << ": " << entry.second << ") "; + } + std::cout << "\n"; + } + } + + int Size() { return size; } + bool IsEmpty() { return table.empty(); } +}; \ No newline at end of file diff --git a/task_08/src/test.cpp b/task_08/src/test.cpp index 5e11617..daa8be3 100644 --- a/task_08/src/test.cpp +++ b/task_08/src/test.cpp @@ -1,6 +1,89 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include + +#include "HashTable.hpp" + +class HashTableTest : public ::testing::Test { + protected: + HashTable ht; +}; + +TEST_F(HashTableTest, InsertAndFind) { + ht.insert("apple", 10); + ht.insert("banana", 20); + ht.insert("orange", 30); + + auto res = ht.find("apple"); + ASSERT_TRUE(res.has_value()); + EXPECT_EQ(res.value(), 10); + + res = ht.find("banana"); + ASSERT_TRUE(res.has_value()); + EXPECT_EQ(res.value(), 20); + + res = ht.find("orange"); + ASSERT_TRUE(res.has_value()); + EXPECT_EQ(res.value(), 30); +} + +TEST_F(HashTableTest, FindNonExistentKey) { + ht.insert("apple", 10); + auto res = ht.find("pear"); + EXPECT_FALSE(res.has_value()); +} + +TEST_F(HashTableTest, InsertOverwriteValue) { + ht.insert("apple", 10); + ht.insert("apple", 50); + + auto res = ht.find("apple"); + ASSERT_TRUE(res.has_value()); + EXPECT_EQ(res.value(), 50); +} + +TEST_F(HashTableTest, EraseExistingKey) { + ht.insert("apple", 10); + ht.insert("banana", 20); + + bool erased = ht.erase("apple"); + EXPECT_TRUE(erased); + + auto res = ht.find("apple"); + EXPECT_FALSE(res.has_value()); + + res = ht.find("banana"); + ASSERT_TRUE(res.has_value()); + EXPECT_EQ(res.value(), 20); +} + +TEST_F(HashTableTest, EraseNonExistentKey) { + ht.insert("apple", 10); + + bool erased = ht.erase("pear"); + EXPECT_FALSE(erased); +} + +TEST_F(HashTableTest, RehashTriggered) { + HashTable small_ht(2); + small_ht.insert("key1", 1); + small_ht.insert("key2", 2); + + EXPECT_TRUE(small_ht.find("key1").has_value()); + EXPECT_TRUE(small_ht.find("key2").has_value()); + + small_ht.insert("key3", 3); + EXPECT_TRUE(small_ht.find("key3").has_value()); } + +TEST_F(HashTableTest, InsertManyAndFindAll) { + for (int i = 0; i < 1000; ++i) { + ht.insert("key" + std::to_string(i), i); + } + for (int i = 0; i < 1000; ++i) { + auto val = ht.find("key" + std::to_string(i)); + ASSERT_TRUE(val.has_value()); + EXPECT_EQ(val.value(), i); + } +} \ No newline at end of file diff --git a/task_09/src/good_table.hpp b/task_09/src/good_table.hpp new file mode 100644 index 0000000..fc89bba --- /dev/null +++ b/task_09/src/good_table.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +class SortedTableChecker { + int n, m; + std::vector> a; + std::vector maxReachForRow; + + public: + SortedTableChecker(const std::vector>& table) : a(table) { + n = (int)a.size(); + m = n > 0 ? (int)a[0].size() : 0; + preprocess(); + } + + void preprocess() { + if (n == 0 || m == 0) return; + + std::vector> maxReachCol(m, std::vector(n)); + + for (int j = 0; j < m; j++) { + maxReachCol[j][n - 1] = n - 1; + for (int i = n - 2; i >= 0; i--) { + if (a[i][j] <= a[i + 1][j]) + maxReachCol[j][i] = maxReachCol[j][i + 1]; + else + maxReachCol[j][i] = i; + } + } + + maxReachForRow.resize(n); + for (int i = 0; i < n; i++) { + int best = i; + for (int j = 0; j < m; j++) { + if (maxReachCol[j][i] > best) best = maxReachCol[j][i]; + } + maxReachForRow[i] = best; + } + + for (int i = 1; i < n; i++) { + if (maxReachForRow[i] < maxReachForRow[i - 1]) + maxReachForRow[i] = maxReachForRow[i - 1]; + } + } + + bool isSortedSegment(int l, int r) const { + if (l < 0 || r >= n || l > r) return false; + return maxReachForRow[l] >= r; + } +}; diff --git a/task_09/src/test.cpp b/task_09/src/test.cpp index a42caa4..69b6e94 100644 --- a/task_09/src/test.cpp +++ b/task_09/src/test.cpp @@ -2,22 +2,73 @@ #include -TEST(CanReachNonDecreasingSegment, 1) { - // ASSERT_EQ(SolveFunction(5, 4, 6, - // std::vector>{{1, 2, 3, 5}, - // {3, 1, 3, 2}, - // {4, 5, 2, 3}, - // {5, 5, 3, 2}, - // {4, 4, 3, 4}}, - // std::vector>{ - // {1, 1}, {2, 5}, {4, 5}, {3, 5}, {1, 3}, {1, - // 5}}), - // (std::vector{"Yes", "No", "Yes", "Yes", "Yes", - // "No"})); +#include "good_table.hpp" +// TEST(CanReachNonDecreasingSegment, 1) { +// ASSERT_EQ(SolveFunction(5, 4, 6, +// std::vector>{{1, 2, 3, 5}, +// {3, 1, 3, 2}, +// {4, 5, 2, 3}, +// {5, 5, 3, 2}, +// {4, 4, 3, 4}}, +// std::vector>{ +// {1, 1}, {2, 5}, {4, 5}, {3, 5}, {1, 3}, {1, +// 5}}), +// (std::vector{"Yes", "No", "Yes", "Yes", "Yes", +// "No"})); +// } + +// TEST(CanReachNonDecreasingSegment, 2) { +// ASSERT_EQ(SolveFunction(1, 1, 1, std::vector>{{1, 1}}, +// std::vector>{{1, 1}}), +// (std::vector{"Yes"})); +// } + +TEST(SortedTableCheckerTest, SingleColumnSorted) { + std::vector> table = {{1}, {2}, {3}, {4}}; + SortedTableChecker checker(table); + EXPECT_TRUE(checker.isSortedSegment(0, 3)); + EXPECT_TRUE(checker.isSortedSegment(1, 2)); + EXPECT_TRUE(checker.isSortedSegment(2, 3)); +} + +TEST(SortedTableCheckerTest, MultiColumnOneSorted) { + std::vector> table = {{3, 2, 1}, {2, 2, 2}, {1, 2, 3}}; + SortedTableChecker checker(table); + EXPECT_TRUE(checker.isSortedSegment(0, 2)); + EXPECT_TRUE(checker.isSortedSegment(1, 2)); + EXPECT_TRUE(checker.isSortedSegment(0, 1)); +} + +TEST(SortedTableCheckerTest, NoSortedColumns) { + std::vector> table = {{3, 3, 3}, {2, 2, 2}, {1, 1, 1}}; + SortedTableChecker checker(table); + EXPECT_FALSE(checker.isSortedSegment(0, 2)); + EXPECT_FALSE(checker.isSortedSegment(1, 2)); } -TEST(CanReachNonDecreasingSegment, 2) { - // ASSERT_EQ(SolveFunction(1, 1, 1, std::vector>{{1, 1}}, - // std::vector>{{1, 1}}), - // (std::vector{"Yes"})); +TEST(SortedTableCheckerTest, AllColumnsSorted) { + std::vector> table = { + {1, 2, 3}, {2, 3, 4}, {3, 4, 5}, {4, 5, 6}}; + SortedTableChecker checker(table); + EXPECT_TRUE(checker.isSortedSegment(0, 3)); + EXPECT_TRUE(checker.isSortedSegment(1, 3)); + EXPECT_TRUE(checker.isSortedSegment(2, 3)); } + +TEST(SortedTableCheckerTest, EdgeCases) { + std::vector> table = {{5}}; + SortedTableChecker checker(table); + EXPECT_TRUE(checker.isSortedSegment(0, 0)); + + std::vector> emptyTable; + SortedTableChecker checkerEmpty(emptyTable); + EXPECT_FALSE(checkerEmpty.isSortedSegment(0, 0)); +} + +TEST(SortedTableCheckerTest, OutOfBoundsQueries) { + std::vector> table = {{1, 2}, {3, 4}}; + SortedTableChecker checker(table); + EXPECT_FALSE(checker.isSortedSegment(-1, 1)); + EXPECT_FALSE(checker.isSortedSegment(0, 2)); + EXPECT_FALSE(checker.isSortedSegment(1, 0)); +} \ No newline at end of file