diff --git a/cpp/101.cpp b/cpp/101.cpp new file mode 100644 index 0000000..0f38703 --- /dev/null +++ b/cpp/101.cpp @@ -0,0 +1,46 @@ +// https://leetcode.com/problems/symmetric-tree/submissions/1292981419/ + +/** + * Definition for a binary tree node. +*/ +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode() : val(0), left(nullptr), right(nullptr) {} + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} +}; + +/** + * Method: + * - Reverse the right-hand side + * - Check whether the left and right are now equal via a pre-order traversal. + * - Time: O(n) + * - Space: O(n). + * + * On my first time, I didn't see that the problem could be solved directly by comparing the trees recursively; + * doing this would still be O(n) time and space, but avoid having to invert the right tree for no other reason. + */ +class Solution { +public: + bool isSymmetric(TreeNode* root) { + reverseBinaryTree(root->right); + return treesAreEqual(root->left, root->right); + } + + void reverseBinaryTree(TreeNode* root) { + if (root == nullptr) return; + TreeNode* temp = root->left; + root->left = root->right; + root->right = temp; + reverseBinaryTree(root->left); + reverseBinaryTree(root->right); + } + + bool treesAreEqual(TreeNode* left, TreeNode* right) { + if (left == nullptr) return right == nullptr; + if (right == nullptr) return left == nullptr; + return (left->val != right->val) && treesAreEqual(left->left, right->left) && treesAreEqual(left->right, right->right); + } +}; diff --git a/cpp/110.cpp b/cpp/110.cpp new file mode 100644 index 0000000..7482369 --- /dev/null +++ b/cpp/110.cpp @@ -0,0 +1,26 @@ +// https://leetcode.com/problems/balanced-binary-tree/submissions/1292988627/ +/** + * Definition for a binary tree node. + */ +#include +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode() : val(0), left(nullptr), right(nullptr) {} + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + }; + +class Solution { +public: + bool isBalanced(TreeNode* root) { + if (root == nullptr) return true; + return std::abs(height(root->left) - height(root->right)) < 2 && isBalanced(root->left) && isBalanced(root->right); + } + + int height(TreeNode* root) { + if (root == nullptr) return 0; + return (root->val = 1 + std::max(height(root->left), height(root->right))); + } +}; diff --git a/cpp/111.cpp b/cpp/111.cpp new file mode 100644 index 0000000..8c6454d --- /dev/null +++ b/cpp/111.cpp @@ -0,0 +1,35 @@ +// https://leetcode.com/problems/minimum-depth-of-binary-tree/ + +/** + * Definition for a binary tree node. +*/ +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode() : val(0), left(nullptr), right(nullptr) {} + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} +}; + +class Solution { +private: + int min = 100001; +public: + int minDepth(TreeNode* root) { + if (root == nullptr) return 0; + return minDepth(root, 1); + } + int minDepth(TreeNode* root, int current) { + if (root == nullptr) { + return min; + } else { + if (root->left == nullptr && root->right == nullptr && current < min) { + min = current; + } + minDepth(root->left, current + 1); + minDepth(root->right, current + 1); + } + return min; + } +}; diff --git a/cpp/141a.cpp b/cpp/141a.cpp new file mode 100644 index 0000000..f865340 --- /dev/null +++ b/cpp/141a.cpp @@ -0,0 +1,32 @@ +// https://leetcode.com/problems/linked-list-cycle/ +// This is my intial, unthoughtful solution. +// Looking at the answers, it would turn out there's a much better method, involving two pointers, which didn't occur to me when I was originally trying to solve it. +// It seemed impossible to me to "remember" whether we've "seen" a specific node before so as to tell whether a cycle has occurred - the type of reasoning being used in this solution - +// but such reasoning is unnecessary under the other method. Please see 141b for that implementation. + +/** + * Definition for singly-linked list. + */ +#include +#include +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(NULL) {} +}; + +class Solution { +public: + bool hasCycle(ListNode *head) { + std::unordered_set seen; + ListNode* current = head; + while (current) { + if (seen.count(current)) { + return true; + } + seen.insert(current); + current = current->next; + } + return false; + } +}; diff --git a/cpp/141b.cpp b/cpp/141b.cpp new file mode 100644 index 0000000..c5deddc --- /dev/null +++ b/cpp/141b.cpp @@ -0,0 +1,33 @@ +// https://leetcode.com/problems/linked-list-cycle/ +/** + * Definition for singly-linked list. + */ +#include +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(NULL) {} +}; + +// Reasoning: +// If we use two pointers, one that moves twice as fast as the other, then the faster one will +// eventually lap the slower one if there's a cycle, as it will go all the way back and catch up to it again. +// In this case, the pointers will eventually become equal, and we can return true, that there is a cycle; +// otherwise, the faster pointer will simply reach the end of the list, so either it or its successor will be null; +// in this case, there must not be a cycle, as it has simply reached the end. +// This begs the question whether this can be done in "O(1)" time by just iterating 10^4 times (as specified as the upper limit of the list's length in the problem). +class Solution { +public: + bool hasCycle(ListNode *head) { + ListNode* slow = head; + ListNode* fast = head; + while (fast && fast->next) { + fast = fast->next->next; + slow = slow->next; + if (fast == slow) { + return true; + } + } + return false; + } +}; diff --git a/cpp/141c.cpp b/cpp/141c.cpp new file mode 100644 index 0000000..358916e --- /dev/null +++ b/cpp/141c.cpp @@ -0,0 +1,29 @@ +// https://leetcode.com/problems/linked-list-cycle/ +/** + * Definition for singly-linked list. + */ +#include +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(NULL) {} +}; + +// Pursuing the cheeky logic from last time, indeed, we can run the loop 10001 times, +// and if the pointer still isn't at the end, we know it must be stuck in a loop +// (since the longest possible list is only 10000). +// This actually performs surprisingly well on the leaderboard, despite being totally, totally +// overkill for almost all the cases :) +class Solution { +public: + bool hasCycle(ListNode *head) { + ListNode* ptr = head; + for (int i = 0; i < 10001; i++) { + if (ptr == nullptr) { + return false; + } + ptr = ptr->next; + } + return true; + } +}; diff --git a/cpp/145a.cpp b/cpp/145a.cpp new file mode 100644 index 0000000..26c5daa --- /dev/null +++ b/cpp/145a.cpp @@ -0,0 +1,26 @@ +/** + * Definition for a binary tree node. + */ +#include +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode() : val(0), left(nullptr), right(nullptr) {} + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} +}; + +class Solution { +private: + std::vector traversal; +public: + std::vector postorderTraversal(TreeNode* root) { + if (root != nullptr) { + postorderTraversal(root->left); + postorderTraversal(root->right); + traversal.push_back(root->val); + } + return traversal; + } +}; diff --git a/cpp/145b (WIP).cpp b/cpp/145b (WIP).cpp new file mode 100644 index 0000000..649ae22 --- /dev/null +++ b/cpp/145b (WIP).cpp @@ -0,0 +1,20 @@ +/** + * Definition for a binary tree node. + */ +#include +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode() : val(0), left(nullptr), right(nullptr) {} + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} +}; + +class Solution { +public: + // TODO: Make this iterative instead of recursive. + std::vector postorderTraversal(TreeNode* root) { + //TODO + } +}; diff --git a/cpp/160a.cpp b/cpp/160a.cpp new file mode 100644 index 0000000..76c096b --- /dev/null +++ b/cpp/160a.cpp @@ -0,0 +1,28 @@ +/** + * Definition for singly-linked list. + */ +#include +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(NULL) {} +}; + +// This solution is not great, being O(n^2)-ish time, although it is O(1) space, which is good. +// There is likely at least an O(n) in both solution... +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + while (headA) { + ListNode* check = headB; + while (check) { + if (check == headA) { + return headA; + } + check = check->next; + } + headA = headA->next; + } + return nullptr; + } +}; diff --git a/cpp/160b.cpp b/cpp/160b.cpp new file mode 100644 index 0000000..43bf3c5 --- /dev/null +++ b/cpp/160b.cpp @@ -0,0 +1,44 @@ +/** + * Definition for singly-linked list. + */ +#include +#include +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(NULL) {} +}; + +// This solution is now O(n) time and O(n) space. +// The method is to copy the linked list nodes into two vectors; +// then, starting from the back, if the elements are not equal from the very end, +// the lists don't intersect ever. +// Otherwise, iterating from the back, find the first node that isn't shared between the lists, +// and then return the node just after that (which is shared by both). +// If we get all the way to the beginning, then the first node of the lists must be the shared one. +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + std::vector listA; + std::vector listB; + for (ListNode* start = headA; start != nullptr; start = start->next) { + listA.push_back(start); + } + for (ListNode* start = headB; start != nullptr; start = start->next) { + listB.push_back(start); + } + int endA = listA.size() - 1; + int endB = listB.size() - 1; + if (listA.at(endA) != listB.at(endB)) { + return nullptr; + } + while (endA >= 0 && endB >= 0) { + if (listA.at(endA) != listB.at(endB)) { + return listA.at(endA + 1); + } + endA--; + endB--; + } + return listA.at(endA + 1); + } +}; diff --git a/cpp/160c.cpp b/cpp/160c.cpp new file mode 100644 index 0000000..ffce78b --- /dev/null +++ b/cpp/160c.cpp @@ -0,0 +1,35 @@ +/** + * Definition for singly-linked list. + */ +#include +struct ListNode { + int val; + ListNode *next; + ListNode(int x) : val(x), next(NULL) {} +}; + +// I couldn't figure this solution out on my own, so I looked it up on YouTube. +// This is my implementation after seeing the method. +// The idea is to use two pointers, and advance both forwards; if the end is reached by either, +// swap that pointer to the beginning of the opposite list. +// Once both pointers have moved all the way to the end, they will be in line with each other; +// by this token, some time before they even reach the end, they will reach their common intersection point, +// and be equal to each other. +// +// Even if they don't intersect, they will still end up equal to each other, both as null pointers. +// +// P.S. for reasons unknown, solution B that I wrote seems to consistently work faster, +// despite being asymptotically slower; and it doesn't even have simpler operations, either. +// I don't know what the cause could be, but... +class Solution { +public: + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + ListNode* a = headA; + ListNode* b = headB; + while (a != b) { + a = a == nullptr ? headB : a->next; + b = b == nullptr ? headA : b->next; + } + return a; + } +}; diff --git a/cpp/168.cpp b/cpp/168.cpp new file mode 100644 index 0000000..e139f6c --- /dev/null +++ b/cpp/168.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +class Solution { +private: + std::array alphabet = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; +public: + std::string convertToTitle(int columnNumber) { + long power = 1; + short length = 0; + while (columnNumber >= power) { + columnNumber -= power; + power *= 26; + length++; + } + + std::string out; + for (; length > 0; length--) { + int remainder = columnNumber % 26; + columnNumber = columnNumber / 26; + char corresponding_char = alphabet.at(remainder); + out.push_back(corresponding_char); + } + + std::reverse(out.begin(), out.end()); + return out; + } + +}; + +int main() { + Solution sol; + for (int i = 1; i < 26*10; i++) { + std::cout << i << " -> " << sol.convertToTitle(i) << '\n'; + } +} diff --git a/cpp/171.cpp b/cpp/171.cpp new file mode 100644 index 0000000..f7f968b --- /dev/null +++ b/cpp/171.cpp @@ -0,0 +1,18 @@ +#include +class Solution { +private: + constexpr int numericValue(char c) { + return (int) (c-'A'); + } +public: + int titleToNumber(std::string columnTitle) { + int value = 0; + int length = columnTitle.length(); + for (long power = 1, i = length-1; i >= 0; power *= 26, i--) { + // value += power; + // value += power * numericValue(columnTitle.at(i)); + value += power * (1 + numericValue(columnTitle.at(i))); + } + return value; + } +}; diff --git a/cpp/190.cpp b/cpp/190.cpp new file mode 100644 index 0000000..98fa198 --- /dev/null +++ b/cpp/190.cpp @@ -0,0 +1,25 @@ +#include +// #include +class Solution { +private: + uint32_t setBit(uint32_t in, char value, char pos) { + uint32_t ones = -1; + uint32_t zero_mask = (ones ^ (value << pos)); + in = in & zero_mask; + in = in ^ (value << pos); + return in; + } +public: + uint32_t reverseBits(uint32_t n) { + uint32_t out = 0; + for (char i = 0; i < 32; i++) { + out = setBit(out, n & 1, 31-i); + n >>= 1; + } + return out; + } +}; + +// int main() { +// std::cout << setBit(8, 1, 3) << std::endl; +// } diff --git a/cpp/65.cpp b/cpp/65.cpp new file mode 100644 index 0000000..8a38ff6 --- /dev/null +++ b/cpp/65.cpp @@ -0,0 +1,84 @@ +#include +#include +class Solution { +private: + int i = 0; + std::string s; + std::vector digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + bool atEnd() { + return this->i == s.length(); + } + + bool test(char c) { + if (atEnd()) { + return false; + } + return s.at(i) == c; + } + bool test(std::vector chars) { + for (char c : chars) { + if (test(c)) { + return true; + } + } + return false; + } + bool match(char c) { + if (test(c)) { + i++; + return true; + } + return false; + } + bool match(std::vector chars) { + if (test(chars)) { + i++; + return true; + } + return false; + } + bool many(std::vector chars) { + bool matched = false; + while (match(chars)) { + matched = true; + } + return matched; + } + bool digitString() { + return many(digits); + } + + bool integer() { + match({'+', '-'}); + return digitString(); + } + + bool decimal() { + if (!integer()) { + return match('.') && digitString(); + } else { + match('.'); + digitString(); + return true; + } + } + + bool exponent() { + if (match({'e', 'E'})) { + return integer(); + } + return true; + } + + bool number() { + bool success = decimal(); + return success && exponent(); + } + +public: + bool isNumber(std::string s) { + this->s = s; + return number() && this->atEnd(); + } +}; diff --git a/cpp/83.cpp b/cpp/83.cpp new file mode 100644 index 0000000..0214e2a --- /dev/null +++ b/cpp/83.cpp @@ -0,0 +1,34 @@ +// https://leetcode.com/problems/remove-duplicates-from-sorted-list/ + +#include + +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) {} + }; + +class Solution { +public: + ListNode* deleteDuplicates(ListNode* head) { + if (head == nullptr) + return head; + bool newSequence = false; + int currentVal = head->val; + ListNode* front = head->next; + ListNode* rear = head; + while (front != nullptr) { + if (front->val != currentVal) { + std::cout << "Previous value: " << currentVal << "; current value: " << front->val << '\n'; + rear->next = front; + currentVal = front->val; + rear = front; + } + front = front->next; + } + rear->next = nullptr; + return head; + } +};