Solve many problems in C++

This commit is contained in:
Kiril Kovachev 2024-06-21 01:36:27 +01:00
parent eaa8414c67
commit b438dd5395
16 changed files with 553 additions and 0 deletions

46
cpp/101.cpp Normal file
View File

@ -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);
}
};

26
cpp/110.cpp Normal file
View File

@ -0,0 +1,26 @@
// https://leetcode.com/problems/balanced-binary-tree/submissions/1292988627/
/**
* Definition for a binary tree node.
*/
#include <algorithm>
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)));
}
};

35
cpp/111.cpp Normal file
View File

@ -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;
}
};

32
cpp/141a.cpp Normal file
View File

@ -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 <cstddef>
#include <unordered_set>
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
bool hasCycle(ListNode *head) {
std::unordered_set<ListNode*> seen;
ListNode* current = head;
while (current) {
if (seen.count(current)) {
return true;
}
seen.insert(current);
current = current->next;
}
return false;
}
};

33
cpp/141b.cpp Normal file
View File

@ -0,0 +1,33 @@
// https://leetcode.com/problems/linked-list-cycle/
/**
* Definition for singly-linked list.
*/
#include <cstddef>
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;
}
};

29
cpp/141c.cpp Normal file
View File

@ -0,0 +1,29 @@
// https://leetcode.com/problems/linked-list-cycle/
/**
* Definition for singly-linked list.
*/
#include <cstddef>
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;
}
};

26
cpp/145a.cpp Normal file
View File

@ -0,0 +1,26 @@
/**
* Definition for a binary tree node.
*/
#include <vector>
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<int> traversal;
public:
std::vector<int> postorderTraversal(TreeNode* root) {
if (root != nullptr) {
postorderTraversal(root->left);
postorderTraversal(root->right);
traversal.push_back(root->val);
}
return traversal;
}
};

20
cpp/145b (WIP).cpp Normal file
View File

@ -0,0 +1,20 @@
/**
* Definition for a binary tree node.
*/
#include <vector>
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<int> postorderTraversal(TreeNode* root) {
//TODO
}
};

28
cpp/160a.cpp Normal file
View File

@ -0,0 +1,28 @@
/**
* Definition for singly-linked list.
*/
#include <cstddef>
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;
}
};

44
cpp/160b.cpp Normal file
View File

@ -0,0 +1,44 @@
/**
* Definition for singly-linked list.
*/
#include <cstddef>
#include <vector>
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<ListNode*> listA;
std::vector<ListNode*> 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);
}
};

35
cpp/160c.cpp Normal file
View File

@ -0,0 +1,35 @@
/**
* Definition for singly-linked list.
*/
#include <cstddef>
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;
}
};

38
cpp/168.cpp Normal file
View File

@ -0,0 +1,38 @@
#include <algorithm>
#include <array>
#include <cmath>
#include <iostream>
#include <string>
class Solution {
private:
std::array<char, 26> 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';
}
}

18
cpp/171.cpp Normal file
View File

@ -0,0 +1,18 @@
#include <string>
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;
}
};

25
cpp/190.cpp Normal file
View File

@ -0,0 +1,25 @@
#include <cstdint>
// #include <iostream>
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;
// }

84
cpp/65.cpp Normal file
View File

@ -0,0 +1,84 @@
#include <string>
#include <vector>
class Solution {
private:
int i = 0;
std::string s;
std::vector<char> 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<char> 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<char> chars) {
if (test(chars)) {
i++;
return true;
}
return false;
}
bool many(std::vector<char> 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();
}
};

34
cpp/83.cpp Normal file
View File

@ -0,0 +1,34 @@
// https://leetcode.com/problems/remove-duplicates-from-sorted-list/
#include <iostream>
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;
}
};