diff --git a/modules/arrays_and_strings/arrays_algorithms.h b/modules/arrays_and_strings/arrays_algorithms.h index 7ed2e2b..f348bb1 100644 --- a/modules/arrays_and_strings/arrays_algorithms.h +++ b/modules/arrays_and_strings/arrays_algorithms.h @@ -10,6 +10,7 @@ bool allUniqueBruteForce(std::string s); std::string inverse(const char* str); bool isPermBruteForce(std::string s1, std::string s2); bool isPerm(const std::string& s1, const std::string& s2); +bool isPalindrome(const std::string& s); std::string URLify(const char* s, int n); bool isPalindromePerm(std::string s); bool oneAway(std::string s1, std::string s2); @@ -17,5 +18,5 @@ std::string strCompression(const std::string& s); std::vector rotate(std::vector mat, int n); std::vector rotateInPlace(std::vector mat, int n); int numberOfIslands(std::vector v, int N, int M); - +void perm(std::string s, int l, int r); #endif // MODULES_ARRAYS_AND_STRINGS_ARRAYS_ALGORITHMS_H_ diff --git a/modules/arrays_and_strings/arrays_alroritms.cpp b/modules/arrays_and_strings/arrays_alroritms.cpp index 10be660..a1c2fc1 100644 --- a/modules/arrays_and_strings/arrays_alroritms.cpp +++ b/modules/arrays_and_strings/arrays_alroritms.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../../modules/arrays_and_strings/arrays_algorithms.h" using std::vector; @@ -218,3 +219,15 @@ int numberOfIslands(vector v, int N, int M) { return count; } + +bool isPalindrome(const std::string& s) { + for (size_t i = 0; i < s.size() / 2; ++i) { + if (s[i] != s[s.size() - i - 1]) + return false; + } + return true; +} + +void perm(const std::string& s) { + std::vector chosen(s.size()); +} diff --git a/modules/arrays_and_strings/main.cpp b/modules/arrays_and_strings/main.cpp index c4d4fbb..5dacd7f 100644 --- a/modules/arrays_and_strings/main.cpp +++ b/modules/arrays_and_strings/main.cpp @@ -224,6 +224,28 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple>({ 0, 0, 0, 0, 1, 0, 0, 0, 0 }, 1), std::make_tuple>({ 1, 1, 1, 0, 0, 1, 1, 0, 0 }, 2))); +class PalindromeTestFixture : public ::testing::TestWithParam> {}; + +TEST_P(PalindromeTestFixture, correctness_is_palindrome) { + std::string s = std::get<0>(GetParam()); + bool expected = std::get<1>(GetParam()); + ASSERT_EQ(isPalindrome(s), expected); +} + + +INSTANTIATE_TEST_SUITE_P( + IsPalindrome, + PalindromeTestFixture, + ::testing::Values( + std::make_tuple("a", true), + std::make_tuple("ab", false), + std::make_tuple("aa", true), + std::make_tuple("aaaa", true), + std::make_tuple("baab", true), + std::make_tuple("aabaa", true), + std::make_tuple("nolemonnomelon", true), + std::make_tuple("nolemoannomelon", false), + std::make_tuple("level", true))); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/modules/linked_lists/CMakeLists.txt b/modules/linked_lists/CMakeLists.txt new file mode 100644 index 0000000..6764298 --- /dev/null +++ b/modules/linked_lists/CMakeLists.txt @@ -0,0 +1,18 @@ +get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME) + +set(ProjectId "${ProjectId}") +project( ${ProjectId} ) +message( STATUS "-- " ${ProjectId} ) + +file(GLOB_RECURSE header_files "*.h") +file(GLOB_RECURSE source_files "*.cpp") +set(PACK_LIB "${ProjectId}_lib") +add_library(${PACK_LIB} STATIC ${header_files} ${source_files}) + +add_executable(${ProjectId} ${source_files}) + +target_link_libraries(${ProjectId} ${PACK_LIB}) +target_link_libraries(${ProjectId} gtest gtest_main) + +enable_testing() +add_test(NAME ${ProjectId} COMMAND ${ProjectId}) \ No newline at end of file diff --git a/modules/linked_lists/linked_lists.cpp b/modules/linked_lists/linked_lists.cpp new file mode 100644 index 0000000..e8af4d2 --- /dev/null +++ b/modules/linked_lists/linked_lists.cpp @@ -0,0 +1,232 @@ +// Copyright 2020 Vikhrev Ivan + +#include +#include +#include "../../modules/linked_lists/linked_lists.h" + +List::List(int n, int d) { + head = new Node; + Node* curr = head; + int i = 0; + while (i < n) { + curr->data = d; + if (i == n - 1) { + curr->next = nullptr; + } else { + curr->next = new Node; + } + curr = curr->next; + ++i; + } +} + +List::List(const std::initializer_list& lst) { + head = new Node; + Node* curr = head; + size_t i = 0; + for (auto el : lst) { + curr->data = el; + if (i == lst.size() - 1) { + curr->next = nullptr; + } else { + curr->next = new Node; + } + curr = curr->next; + ++i; + } +} + +List::List(const List& l) { + head = new Node; + Node* curr1 = head; + Node* curr2 = l.head; + while (curr2) { + curr1->data = curr2->data; + if (curr2->next == nullptr) + curr1->next = nullptr; + else + curr1->next = new Node; + curr1 = curr1->next; + curr2 = curr2->next; + } +} + +List::~List() { + Node* curr = head; + while (curr) { + curr = head->next; + delete head; + head = curr; + } +} + +int List::back() const { + if (head) { + Node* curr = head; + while (curr->next) { + curr = curr->next; + } + return curr->data; + } + return 0; +} + +void List::push_back(int d) { + if (head) { + Node* curr = head; + while (curr->next) { + curr = curr->next; + } + curr->next = new Node(d); + } else { + head = new Node(d); + } +} + +bool List::operator==(const List& l) const { + Node* curr1 = head; + Node* curr2 = l.head; + + while (curr1 && curr2) { + if ((*curr1).data == curr2->data) { + curr1 = curr1->next; + curr2 = curr2->next; + } else { + return false; + } + } + + return curr1 == curr2; +} + +void List::remove_duplicates1() { + std::unordered_set s; + if (!empty()) { + s.insert(head->data); + Node* prev = head; + Node* curr = head->next; + while (curr) { + if (s.find(curr->data) == s.end()) { + s.insert(curr->data); + prev = prev->next; + } else { + prev->next = curr->next; + } + curr = curr->next; + } + } +} + +void List::remove_duplicates2() { + if (!empty()) { + Node* p1 = head, *prev = head; + Node* p2; + while (p1) { + p2 = p1->next; + while (p2) { + if (p1->data == p2->data) { + prev->next = p2->next; + } else { + prev = prev->next; + } + p2 = p2->next; + } + p1 = p1->next; + prev = p1; + } + } +} + +// not stable +void List::rearrangeBadImpl(int x) { + Node* start, *end, *curr; + start = end = curr = head; + curr = curr->next; + while (curr) { + Node* tmp = curr; + curr = curr->next; + if (tmp->data < x) { + tmp->next = start; + start = tmp; + } else { + end->next = tmp; + end = tmp; + } + } + end->next = nullptr; + head = start; +} + +// stable +void List::rearrange(int x) { + if (head) { + Node *lessHead = nullptr, *lessCurr = nullptr, + *greaterHead = nullptr, *greaterCurr = nullptr, + *curr = nullptr; + + curr = head; + while (curr) { + Node* tmp = curr; + curr = curr->next; + if (tmp->data < x) { + if (!lessHead) { + lessHead = tmp; + lessCurr = lessHead; + } else { + lessCurr->next = tmp; + lessCurr = lessCurr->next; + } + lessCurr->next = nullptr; + } else { + if (!greaterHead) { + greaterHead = tmp; + greaterCurr = greaterHead; + } else { + greaterCurr->next = tmp; + greaterCurr = greaterCurr->next; + } + greaterCurr->next = nullptr; + } + } + if (lessHead) { + head = lessHead; + lessCurr->next = greaterHead; + } else { + head = greaterHead; + } + } +} + +// assuming that 0 from end is end +int List::find_k_from_end(int k) { + Node* curr = head; + Node* kth = head; + int i = 0; + + while (curr) { + if (i > k) { + kth = kth->next; + } + ++i; + curr = curr->next; + } + + return kth->data; +} +std::ostream& operator<<(std::ostream& os, const List& l) { + Node *curr = l.head; + if (l.head) { + int i = 0; + while (curr) { + if (curr->next == nullptr) + os << curr->data; + else + os << curr->data << "-->"; + i++; + curr = curr->next; + } + } else { + os << "empty"; + } + return os; +} diff --git a/modules/linked_lists/linked_lists.h b/modules/linked_lists/linked_lists.h new file mode 100644 index 0000000..1175ac4 --- /dev/null +++ b/modules/linked_lists/linked_lists.h @@ -0,0 +1,44 @@ +// Copyright 2020 Vikhrev Ivan + +#include +#include +#ifndef MODULES_LINKED_LISTS_LINKED_LISTS_H_ +#define MODULES_LINKED_LISTS_LINKED_LISTS_H_ + +struct Node { + Node* next; + int data; + Node() : next(nullptr), data(0) {} + explicit Node(int d) : next(nullptr), data(d) {} + Node(Node* n, int d) : next(n), data(d) {} + bool operator==(const Node& n) const { return (data == n.data && next == n.next); } + bool operator!=(const Node& n) const { return !(*this == n); } +}; + +class List { + private: + Node* head; + public: + List() : head(nullptr) {} + explicit List(int d) {head = new Node(d);} + List(int n, int d); + List(const List& l); + List(const std::initializer_list& lst); + ~List(); + Node* get_head() const { return head; } + void push_front(int d) { head = new Node(head, d); } + void push_back(int d); + int front() const { return head ? head->data : 0; } + int back() const; + bool empty() const { return !head; } + bool operator==(const List& l) const; + bool operator!=(const List& l) const {return !(*this == l);} + friend std::ostream& operator<<(std::ostream& os, const List& l); + void remove_duplicates1(); + void remove_duplicates2(); + void rearrangeBadImpl(int x); + void rearrange(int x); + int find_k_from_end(int k); +}; + +#endif // MODULES_LINKED_LISTS_LINKED_LISTS_H_ diff --git a/modules/linked_lists/main.cpp b/modules/linked_lists/main.cpp new file mode 100644 index 0000000..03fe15e --- /dev/null +++ b/modules/linked_lists/main.cpp @@ -0,0 +1,218 @@ +// Copyright 2020 Vikhrev Ivan + +#include +#include +#include +#include "gtest/gtest.h" +#include "../../modules/linked_lists/linked_lists.h" + +using std::vector; +// class ListTest : public ::testing:Test { +// protected: +// List l; +// void SetUp() override { +// } + +// void TearDown override { + +// } +// } + +TEST(Node, can_create_node) { + ASSERT_NO_THROW(Node n); +} + +TEST(Node, can_create_node_with_params) { + ASSERT_NO_THROW(Node n(nullptr, 1)); +} + +TEST(Node, node_init_is_correct) { + Node n(nullptr, 1); + ASSERT_EQ(n.next, nullptr); + ASSERT_EQ(n.data, 1); +} + +TEST(Node, eq_nodes_are_eq) { + Node n1(nullptr, 1); + Node n2(nullptr, 1); + ASSERT_EQ(n1, n2); +} + + +TEST(Node, not_eq_nodes_arent_eq1) { + Node n1(nullptr, 1); + Node n2(nullptr, 2); + ASSERT_NE(n1, n2); +} + +TEST(Node, not_eq_nodes_arent_eq2) { + Node n1(nullptr, 1); + Node n2(&n1, 1); + ASSERT_NE(n1, n2); +} + +TEST(Node, not_eq_nodes_arent_eq3) { + Node n1(nullptr, 1); + Node n2(&n1, 2); + ASSERT_NE(n1, n2); +} + +TEST(List, can_create_list) { + ASSERT_NO_THROW(List l); +} + +TEST(List, can_create_list_with_param) { + ASSERT_NO_THROW(List l(1, 1)); +} + + +TEST(List, list_init_with_param_is_correct) { + List l(10, 3); + Node* curr = l.get_head(); + int i = 0; + while (curr->next) { + ++i; + curr = curr->next; + } + ASSERT_EQ(i, 9); + ASSERT_EQ(l.front(), l.back()); +} + +TEST(List, ist_init_with_init_list) { + List l{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::cout << l << std::endl; + ASSERT_EQ(l.front(), 1); + ASSERT_EQ(l.back(), 10); +} + +TEST(List, can_copy_list) { + List l{1, 2, 3, 4}; + ASSERT_NO_THROW(List l2(l)); +} + +TEST(List, copied_list_eq_original) { + List l{1, 2, 3, 4}; + List l2(l); + std::cout << l2 << std::endl; + ASSERT_EQ(l, l2); +} + +TEST(List, push_back_to_empty_list) { + List l; + l.push_back(100); + ASSERT_EQ(l.front(), l.back()); +} + +TEST(List, push_front_to_empty_list) { + List l; + l.push_front(100); + ASSERT_EQ(l.front(), l.back()); +} + +TEST(List, push_back_to_list) { + List l(10, 1); + l.push_back(10); + ASSERT_EQ(l.front(), 1); + ASSERT_EQ(l.back(), 10); +} + +TEST(List, push_front_to_list) { + List l(10, 1); + l.push_front(0); + ASSERT_EQ(l.front(), 0); + ASSERT_EQ(l.back(), 1); +} + +TEST(List, empty_list_is_empty) { + List l; + ASSERT_EQ(l.empty(), true); +} + +TEST(List, not_empty_list_isnt_empty) { + List l(1); + ASSERT_EQ(l.empty(), false); +} + + +TEST(List, eq_lists_are_eq) { + List l1{1, 2, 3, 4, 5}; + List l2{1, 2, 3, 4, 5}; + ASSERT_EQ(l1, l2); +} + + +TEST(List, not_eq_lists_arent_eq) { + List l1(1); + List l2(2); + ASSERT_NE(l1, l2); +} + +class ListParameterizedTestFixture : public ::testing::TestWithParam> {}; + +TEST_P(ListParameterizedTestFixture, can_remove_duplicates_with_unordered_set) { + List l = std::get<0>(GetParam()); + List expected = std::get<1>(GetParam()); + l.remove_duplicates1(); + ASSERT_EQ(l, expected); +} + +TEST_P(ListParameterizedTestFixture, can_remove_duplicates_without_temporary_buffer) { + List l = std::get<0>(GetParam()); + List expected = std::get<1>(GetParam()); + + l.remove_duplicates2(); + std::cout << l << std::endl; + ASSERT_EQ(l, expected); +} + +INSTANTIATE_TEST_SUITE_P( + RemoveDuplicatesTest, + ListParameterizedTestFixture, + ::testing::Values( + std::make_tuple({ 1 }, { 1 }), + std::make_tuple({ 1, 1, 0, 0 }, { 1, 0 }), + std::make_tuple({ 1, 1, 1, 1 }, { 1 }), + std::make_tuple({ 1, 1, 1, 0 }, { 1, 0 }), + std::make_tuple({ 1, 2, 3, 4, 5, 6, 7, 8, 9}, { 1, 2, 3, 4, 5, 6, 7, 8, 9}), + std::make_tuple + ({ 1, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 9}, { 1, 2, 3, 4, 5, 6, 7, 8, 9}))); + +class ListParameterizedWith3ParamsTestFixture : + public ::testing::TestWithParam, List>> {}; + +TEST_P(ListParameterizedWith3ParamsTestFixture, can_rearrange) { + List l = std::get<0>(std::get<0>(GetParam())); + int x = std::get<1>(std::get<0>(GetParam())); + List expected = std::get<1>(GetParam()); + l.rearrange(x); + std::cout << l << std::endl; + ASSERT_EQ(l, expected); +} + +INSTANTIATE_TEST_SUITE_P( + RearrangeTest, + ListParameterizedWith3ParamsTestFixture, + ::testing::Values( + std::make_tuple, List> + (std::make_tuple({1}, 1), {1}), + std::make_tuple, List> + (std::make_tuple({5, 1}, 3), {1, 5}), + std::make_tuple, List> + (std::make_tuple({5, 1, 1, 1}, 3), {1, 1, 1, 5}), + std::make_tuple, List> + (std::make_tuple({5, 4, 2, 1, 2, 3, 4, 5}, 2), {1, 5, 4, 2, 2, 3, 4, 5}), + std::make_tuple, List> + (std::make_tuple({1, 2, 3, 4, 5, 6, 7}, 3), {1, 2, 3, 4, 5, 6, 7}), + std::make_tuple, List> + (std::make_tuple({ 4, 4, 4, 1, 1, 8, 8, 0, 0, 0 }, 2), {1, 1, 0, 0, 0, 4, 4, 4, 8, 8}))); + + +TEST(List, kth_from_the_end) { + List l1{ 1, 2, 3, 4, 5, 6, 7}; + ASSERT_EQ(l1.find_k_from_end(6), 1); +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}