problems(cpp): add „234. Palindrome Linked List“
Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
parent
504fc1ba67
commit
13c5b4b30a
1 changed files with 172 additions and 0 deletions
172
problems/palindrome-linked-list.cpp
Normal file
172
problems/palindrome-linked-list.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* struct ListNode {
|
||||
* int val;
|
||||
* ListNode *next;
|
||||
* ListNode() : val(0), next(nullptr) {}
|
||||
* ListNode(int x) : val(x), next(nullptr) {}
|
||||
* ListNode(int x, ListNode *next) : val(x), next(next) {}
|
||||
* };
|
||||
*/
|
||||
|
||||
struct ListNode {
|
||||
int val;
|
||||
ListNode* next;
|
||||
ListNode()
|
||||
: val(0)
|
||||
, next(nullptr)
|
||||
{
|
||||
}
|
||||
ListNode(int x)
|
||||
: val(x)
|
||||
, next(nullptr)
|
||||
{
|
||||
}
|
||||
ListNode(int x, ListNode* next)
|
||||
: val(x)
|
||||
, next(next)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
struct middle_t {
|
||||
ListNode* node;
|
||||
std::size_t size;
|
||||
|
||||
middle_t(ListNode* node, std::size_t size)
|
||||
: node(node)
|
||||
, size(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
middle_t
|
||||
find_middle(ListNode* head)
|
||||
{
|
||||
ListNode* slow = head;
|
||||
ListNode* fast = head->next;
|
||||
|
||||
std::size_t size;
|
||||
for (size = 0; fast != nullptr && fast->next != nullptr; size++) {
|
||||
slow = slow->next;
|
||||
fast = fast->next->next;
|
||||
}
|
||||
|
||||
return { slow, size };
|
||||
}
|
||||
|
||||
ListNode* reverse_list(ListNode* tail)
|
||||
{
|
||||
ListNode* previous = nullptr;
|
||||
ListNode* next = nullptr;
|
||||
|
||||
for (ListNode* current = tail; current != nullptr; previous = current, current = next) {
|
||||
next = current->next;
|
||||
current->next = previous;
|
||||
}
|
||||
|
||||
return previous;
|
||||
}
|
||||
|
||||
bool compare_lists(ListNode* left, ListNode* right, std::size_t size)
|
||||
{
|
||||
for (auto i = 0u; i < size + 1; i++) {
|
||||
if (left->val != right->val) {
|
||||
return false;
|
||||
}
|
||||
left = left->next;
|
||||
right = right->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class Solution {
|
||||
public:
|
||||
bool isPalindrome(ListNode* head)
|
||||
{
|
||||
// find middle of the linked list
|
||||
auto mid = find_middle(head);
|
||||
|
||||
// reverse the tail of the linked list
|
||||
auto tail = reverse_list(mid.node);
|
||||
|
||||
// compare head and tail
|
||||
return compare_lists(head, tail, mid.size);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma region Testing utilities
|
||||
namespace {
|
||||
|
||||
ListNode*
|
||||
construct_list(const std::vector<int>& values)
|
||||
{
|
||||
ListNode* head = new ListNode(values.front());
|
||||
ListNode* tail = head;
|
||||
|
||||
for (std::size_t i = 1; i < values.size(); i++) {
|
||||
tail->next = new ListNode(values[i]);
|
||||
tail = tail->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void destroy_list(ListNode* linked_list)
|
||||
{
|
||||
if (linked_list == nullptr) {
|
||||
return;
|
||||
}
|
||||
destroy_list(linked_list->next);
|
||||
delete linked_list;
|
||||
}
|
||||
|
||||
bool test_find_middle(const std::vector<int>& values, int mid_value)
|
||||
{
|
||||
auto linked_list = construct_list(values);
|
||||
|
||||
auto mid = find_middle(linked_list);
|
||||
auto result = mid.node->val == mid_value;
|
||||
|
||||
destroy_list(linked_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool test_isPalindrome(const std::vector<int>& values)
|
||||
{
|
||||
auto linked_list = construct_list(values);
|
||||
|
||||
Solution s;
|
||||
auto result = s.isPalindrome(linked_list);
|
||||
|
||||
destroy_list(linked_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#pragma endregion // Testing utilities
|
||||
|
||||
int main()
|
||||
{
|
||||
// find_middle tests
|
||||
assert(test_find_middle(std::vector { 1, 2, 2, 1 }, 2));
|
||||
assert(test_find_middle(std::vector { 1, 2, 3, 2, 1 }, 3));
|
||||
assert(test_find_middle(std::vector { 1, 2 }, 1));
|
||||
assert(test_find_middle(std::vector { 1 }, 1));
|
||||
|
||||
// isPalindrome tests
|
||||
assert(test_isPalindrome(std::vector { 1, 2, 2, 1 }));
|
||||
assert(test_isPalindrome(std::vector { 1, 2, 3, 2, 1 }));
|
||||
assert(!test_isPalindrome(std::vector { 1, 2 }));
|
||||
assert(test_isPalindrome(std::vector { 1 }));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue