From c8887a234737667c05c46dc61850d66702d1b11b Mon Sep 17 00:00:00 2001 From: aa0 <71089234+Ahmad-A0@users.noreply.github.com> Date: Mon, 22 Aug 2022 16:46:19 +0100 Subject: [PATCH] copy cpp files to fit directory structure --- cpp/1-Two-Sum.cpp | 30 +++++ cpp/10-Regular-Expression-Matching.cpp | 49 ++++++++ cpp/100-Same-Tree.cpp | 36 ++++++ cpp/102-Binary-Tree-Level-Order-Traversal.cpp | 57 ++++++++++ cpp/104-Maximum-Depth-Of-Binary-Tree.cpp | 56 +++++++++ cpp/1046-Last-Stone-Weight.cpp | 35 ++++++ ...-Binary-Tree-From-Preorder-And-Inorder.cpp | 50 +++++++++ cpp/11-Container-With-Most-Water.cpp | 33 ++++++ cpp/110-Balanced-Binary-Tree.cpp | 47 ++++++++ cpp/1143-Longest-Common-Subsequence.cpp | 37 ++++++ cpp/115-Distinct-Subsequences.cpp | 41 +++++++ cpp/121-Best-Time-To-Buy-And-Sell-Stock.cpp | 24 ++++ cpp/124-Binary-Tree-Maximum-Path-Sum.cpp | 42 +++++++ cpp/125-Valid-Palindrome.cpp | 33 ++++++ cpp/127-Word-Ladder.cpp | 55 +++++++++ cpp/128-Longest-Consecutive-Sequence.cpp | 29 +++++ cpp/130-Surrounded-Regions.cpp | 52 +++++++++ cpp/131-Palindrome-Partitioning.cpp | 44 ++++++++ cpp/133-Clone-Graph.cpp | 83 ++++++++++++++ cpp/134-Gas-Station.cpp | 39 +++++++ cpp/136-Single-Number.cpp | 22 ++++ cpp/138-Copy-List-With-Random-Pointer.cpp | 101 +++++++++++++++++ cpp/139-Word-Break.cpp | 37 ++++++ cpp/141-Linked-List-Cycle.cpp | 38 +++++++ cpp/143-Reorder-List.cpp | 75 +++++++++++++ cpp/1448-Count-Good-Nodes-In-Binary-Tree.cpp | 41 +++++++ cpp/146-Lru-Cache.cpp | 94 ++++++++++++++++ cpp/15-3sum.cpp | 59 ++++++++++ cpp/150-Evaluate-Reverse-Polish-Notation.cpp | 43 +++++++ cpp/152-Maximum-Product-Subarray.cpp | 30 +++++ ...3-Find-Minimum-In-Rotated-Sorted-Array.cpp | 36 ++++++ cpp/155-Min-Stack.cpp | 55 +++++++++ cpp/1584-Min-Cost-To-Connect-All-Points.cpp | 54 +++++++++ cpp/167-Two-Sum-II.cpp | 34 ++++++ cpp/17-Letter-Combinations-Phone-Number.cpp | 47 ++++++++ ...Minimum-Interval-To-Include-Each-Query.cpp | 54 +++++++++ ...-Merge-Triplets-To-Form-Target-Triplet.cpp | 30 +++++ cpp/19-Remove-Nth-Node-From-End-Of-List.cpp | 48 ++++++++ cpp/190-Reverse-Bits.cpp | 24 ++++ cpp/191-Number-Of-1-Bits.cpp | 27 +++++ cpp/198-House-Robber.cpp | 27 +++++ cpp/199-Binary-Tree-Right-Side-View.cpp | 55 +++++++++ cpp/2-Add-Two-Numbers.cpp | 53 +++++++++ cpp/20-Valid-Parentheses.cpp | 41 +++++++ cpp/20-Valid-Parenthesis-String.cpp | 43 +++++++ cpp/200-Number-Of-Islands.cpp | 41 +++++++ cpp/2013-Detect-Squares.cpp | 53 +++++++++ cpp/202-Happy-Number.cpp | 39 +++++++ cpp/206-Reverse-Linked-List.cpp | 41 +++++++ cpp/207-Course-Schedule.cpp | 48 ++++++++ cpp/208-Implement-Trie-Prefix-Tree.cpp | 83 ++++++++++++++ cpp/21-Merge-Two-Sorted-Lists.cpp | 63 +++++++++++ cpp/210-Course-Schedule-II.cpp | 56 +++++++++ ...gn-Add-And-Search-Words-Data-Structure.cpp | 75 +++++++++++++ cpp/212-Word-Search-II.cpp | 89 +++++++++++++++ cpp/213-House-Robber-II.cpp | 40 +++++++ cpp/215-Kth-Largest-Element-In-Array.cpp | 67 +++++++++++ cpp/217-Contains-Duplicate.cpp | 25 +++++ cpp/22-Generate-Parentheses.cpp | 31 +++++ cpp/226-Invert-Binary-Tree.cpp | 33 ++++++ cpp/23-Merge-K-Sorted-Lists.cpp | 106 ++++++++++++++++++ cpp/230-Kth-Smallest-Element-In-A-Bst.cpp | 42 +++++++ ...ommon-Ancestor-Of-A-Binary-Search-Tree.cpp | 47 ++++++++ cpp/238-Product-Of-Array-Except-Self.cpp | 32 ++++++ cpp/239-Sliding-Window-Maximum.cpp | 39 +++++++ cpp/242-Valid-Anagram-Hashmap.cpp | 21 ++++ cpp/242-Valid-Anagram.cpp | 32 ++++++ cpp/25-Reverse-Nodes-In-K-Group.cpp | 58 ++++++++++ cpp/252-Meeting-Rooms.cpp | 26 +++++ cpp/253-Meeting-Rooms-II.cpp | 32 ++++++ cpp/261-Graph-Valid-Tree.cpp | 49 ++++++++ cpp/268-Missing-Number.cpp | 25 +++++ cpp/271-Encode-And-Decode-Strings.cpp | 48 ++++++++ cpp/286-Walls-And-Gates.cpp | 46 ++++++++ cpp/287-Find-The-Duplicate-Number.cpp | 30 +++++ cpp/295-Find-Median-From-Data-Stream.cpp | 66 +++++++++++ ...-Serialize-And-Deserialize-Binary-Tree.cpp | 69 ++++++++++++ ...Substring-Without-Repeating-Characters.cpp | 34 ++++++ cpp/300-Longest-Increasing-Subsequence.cpp | 40 +++++++ ...me-To-Buy-And-Sell-Stock-With-Cooldown.cpp | 48 ++++++++ cpp/312-Burst-Balloons.cpp | 52 +++++++++ cpp/322-Coin-Change.cpp | 30 +++++ ...cted-Components-In-An-Undirected-Graph.cpp | 57 ++++++++++ ...29-Longest-Increasing-Path-In-A-Matrix.cpp | 48 ++++++++ cpp/33-Search-In-Rotated-Sorted-Array.cpp | 39 +++++++ cpp/332-Reconstruct-Itinerary.cpp | 37 ++++++ cpp/338-Counting-Bits.cpp | 25 +++++ cpp/347-Top-K-Frequent-Elements.cpp | 65 +++++++++++ cpp/355-Design-Twitter.cpp | 65 +++++++++++ cpp/36-Valid-Sudoku.cpp | 38 +++++++ cpp/371-Sum-Of-Two-Integers.cpp | 21 ++++ cpp/39-Combination-Sum.cpp | 37 ++++++ cpp/4-Median-Of-Two-Sorted-Arrays.cpp | 62 ++++++++++ cpp/40-Combination-Sum-II.cpp | 40 +++++++ cpp/416-Partition-Equal-Subset-Sum.cpp | 42 +++++++ cpp/417-Pacific-Atlantic-Water-Flow.cpp | 61 ++++++++++ cpp/42-Trapping-Rain-Water.cpp | 38 +++++++ ...ongest-Repeating-Character-Replacement.cpp | 36 ++++++ cpp/43-Multiply-Strings.cpp | 34 ++++++ cpp/435-Non-Overlapping-Intervals.cpp | 38 +++++++ cpp/45-Jump-Game-II.cpp | 37 ++++++ cpp/46-Permutations.cpp | 30 +++++ cpp/48-Rotate-Image.cpp | 21 ++++ cpp/49-Group-Anagrams.cpp | 39 +++++++ cpp/494-Target-Sum.cpp | 34 ++++++ cpp/5-Longest-Palindrome-Substring.cpp | 35 ++++++ cpp/50-Pow-X-N.cpp | 56 +++++++++ cpp/51-N-Queens.cpp | 50 +++++++++ cpp/518-Coin-Change-2.cpp | 39 +++++++ cpp/53-Maximum-Subarray.cpp | 24 ++++ cpp/54-Spiral-Matrix.cpp | 48 ++++++++ cpp/543-Diameter-Of-Binary-Tree.cpp | 40 +++++++ cpp/55-Jump-Game.cpp | 29 +++++ cpp/56-Merge-Intervals.cpp | 39 +++++++ cpp/567-Permutation-In-String.cpp | 48 ++++++++ cpp/57-Insert-Interval.cpp | 38 +++++++ cpp/572-Subtree-Of-Another-Tree.cpp | 45 ++++++++ cpp/62-Unique-Paths.cpp | 31 +++++ cpp/621-Task-Scheduler.cpp | 40 +++++++ cpp/647-Palindromic-Substrings.cpp | 31 +++++ cpp/66-Plus-One.cpp | 26 +++++ cpp/684-Redundant-Connection.cpp | 64 +++++++++++ cpp/695-Max-Area-Of-Island.cpp | 38 +++++++ cpp/7-Reverse-Integer.cpp | 28 +++++ cpp/70-Climbing-Stairs.cpp | 36 ++++++ cpp/703-Kth-Largest-Element-In-A-Stream.cpp | 39 +++++++ cpp/704-Binary-Search.cpp | 30 +++++ cpp/72-Edit-Distance.cpp | 77 +++++++++++++ cpp/73-Set-Matrix-Zeroes.cpp | 62 ++++++++++ cpp/739-Daily-Temperatures.cpp | 37 ++++++ cpp/74-Search-A-2d-Matrix.cpp | 49 ++++++++ cpp/743-Network-Delay-Time.cpp | 63 +++++++++++ cpp/746-Min-Cost-Climbing-Stairs.cpp | 27 +++++ cpp/76-Minimum-Window-Substring.cpp | 62 ++++++++++ cpp/763-Partition-Labels.cpp | 38 +++++++ cpp/778-Swim-In-Rising-Water.cpp | 54 +++++++++ cpp/78-Subsets.cpp | 28 +++++ cpp/787-Cheapest-Flights-Within-K-Stops.cpp | 78 +++++++++++++ cpp/79-Word-Search.cpp | 51 +++++++++ cpp/84-Largest-Rectangle-In-Histogram.cpp | 44 ++++++++ cpp/846-Hand-Of-Straights.cpp | 41 +++++++ cpp/853-Car-Fleet.cpp | 37 ++++++ cpp/875-Koko-Eating-Bananas.cpp | 41 +++++++ ...o-Eating-Bananas.cpp-Hand-Of-Straights.cpp | 41 +++++++ cpp/90-Subsets-II.cpp | 34 ++++++ cpp/91-Decode-Ways.cpp | 38 +++++++ cpp/953-Alien-Dictionary.cpp | 99 ++++++++++++++++ cpp/97-Interleaving-String.cpp | 41 +++++++ cpp/973-K-Closest-Points-To-Origin.cpp | 74 ++++++++++++ cpp/98-Validate-Binary-Search-Tree.cpp | 74 ++++++++++++ cpp/981-Time-Based-Key-Value-Store.cpp | 53 +++++++++ cpp/994-Rotting-Oranges.cpp | 74 ++++++++++++ 152 files changed, 6911 insertions(+) create mode 100644 cpp/1-Two-Sum.cpp create mode 100644 cpp/10-Regular-Expression-Matching.cpp create mode 100644 cpp/100-Same-Tree.cpp create mode 100644 cpp/102-Binary-Tree-Level-Order-Traversal.cpp create mode 100644 cpp/104-Maximum-Depth-Of-Binary-Tree.cpp create mode 100644 cpp/1046-Last-Stone-Weight.cpp create mode 100644 cpp/105-Construct-Binary-Tree-From-Preorder-And-Inorder.cpp create mode 100644 cpp/11-Container-With-Most-Water.cpp create mode 100644 cpp/110-Balanced-Binary-Tree.cpp create mode 100644 cpp/1143-Longest-Common-Subsequence.cpp create mode 100644 cpp/115-Distinct-Subsequences.cpp create mode 100644 cpp/121-Best-Time-To-Buy-And-Sell-Stock.cpp create mode 100644 cpp/124-Binary-Tree-Maximum-Path-Sum.cpp create mode 100644 cpp/125-Valid-Palindrome.cpp create mode 100644 cpp/127-Word-Ladder.cpp create mode 100644 cpp/128-Longest-Consecutive-Sequence.cpp create mode 100644 cpp/130-Surrounded-Regions.cpp create mode 100644 cpp/131-Palindrome-Partitioning.cpp create mode 100644 cpp/133-Clone-Graph.cpp create mode 100644 cpp/134-Gas-Station.cpp create mode 100644 cpp/136-Single-Number.cpp create mode 100644 cpp/138-Copy-List-With-Random-Pointer.cpp create mode 100644 cpp/139-Word-Break.cpp create mode 100644 cpp/141-Linked-List-Cycle.cpp create mode 100644 cpp/143-Reorder-List.cpp create mode 100644 cpp/1448-Count-Good-Nodes-In-Binary-Tree.cpp create mode 100644 cpp/146-Lru-Cache.cpp create mode 100644 cpp/15-3sum.cpp create mode 100644 cpp/150-Evaluate-Reverse-Polish-Notation.cpp create mode 100644 cpp/152-Maximum-Product-Subarray.cpp create mode 100644 cpp/153-Find-Minimum-In-Rotated-Sorted-Array.cpp create mode 100644 cpp/155-Min-Stack.cpp create mode 100644 cpp/1584-Min-Cost-To-Connect-All-Points.cpp create mode 100644 cpp/167-Two-Sum-II.cpp create mode 100644 cpp/17-Letter-Combinations-Phone-Number.cpp create mode 100644 cpp/1851-Minimum-Interval-To-Include-Each-Query.cpp create mode 100644 cpp/1899-Merge-Triplets-To-Form-Target-Triplet.cpp create mode 100644 cpp/19-Remove-Nth-Node-From-End-Of-List.cpp create mode 100644 cpp/190-Reverse-Bits.cpp create mode 100644 cpp/191-Number-Of-1-Bits.cpp create mode 100644 cpp/198-House-Robber.cpp create mode 100644 cpp/199-Binary-Tree-Right-Side-View.cpp create mode 100644 cpp/2-Add-Two-Numbers.cpp create mode 100644 cpp/20-Valid-Parentheses.cpp create mode 100644 cpp/20-Valid-Parenthesis-String.cpp create mode 100644 cpp/200-Number-Of-Islands.cpp create mode 100644 cpp/2013-Detect-Squares.cpp create mode 100644 cpp/202-Happy-Number.cpp create mode 100644 cpp/206-Reverse-Linked-List.cpp create mode 100644 cpp/207-Course-Schedule.cpp create mode 100644 cpp/208-Implement-Trie-Prefix-Tree.cpp create mode 100644 cpp/21-Merge-Two-Sorted-Lists.cpp create mode 100644 cpp/210-Course-Schedule-II.cpp create mode 100644 cpp/211-Design-Add-And-Search-Words-Data-Structure.cpp create mode 100644 cpp/212-Word-Search-II.cpp create mode 100644 cpp/213-House-Robber-II.cpp create mode 100644 cpp/215-Kth-Largest-Element-In-Array.cpp create mode 100644 cpp/217-Contains-Duplicate.cpp create mode 100644 cpp/22-Generate-Parentheses.cpp create mode 100644 cpp/226-Invert-Binary-Tree.cpp create mode 100644 cpp/23-Merge-K-Sorted-Lists.cpp create mode 100644 cpp/230-Kth-Smallest-Element-In-A-Bst.cpp create mode 100644 cpp/235-Lowest-Common-Ancestor-Of-A-Binary-Search-Tree.cpp create mode 100644 cpp/238-Product-Of-Array-Except-Self.cpp create mode 100644 cpp/239-Sliding-Window-Maximum.cpp create mode 100644 cpp/242-Valid-Anagram-Hashmap.cpp create mode 100644 cpp/242-Valid-Anagram.cpp create mode 100644 cpp/25-Reverse-Nodes-In-K-Group.cpp create mode 100644 cpp/252-Meeting-Rooms.cpp create mode 100644 cpp/253-Meeting-Rooms-II.cpp create mode 100644 cpp/261-Graph-Valid-Tree.cpp create mode 100644 cpp/268-Missing-Number.cpp create mode 100644 cpp/271-Encode-And-Decode-Strings.cpp create mode 100644 cpp/286-Walls-And-Gates.cpp create mode 100644 cpp/287-Find-The-Duplicate-Number.cpp create mode 100644 cpp/295-Find-Median-From-Data-Stream.cpp create mode 100644 cpp/297-Serialize-And-Deserialize-Binary-Tree.cpp create mode 100644 cpp/3-Longest-Substring-Without-Repeating-Characters.cpp create mode 100644 cpp/300-Longest-Increasing-Subsequence.cpp create mode 100644 cpp/309-Best-Time-To-Buy-And-Sell-Stock-With-Cooldown.cpp create mode 100644 cpp/312-Burst-Balloons.cpp create mode 100644 cpp/322-Coin-Change.cpp create mode 100644 cpp/323-Number-Of-Connected-Components-In-An-Undirected-Graph.cpp create mode 100644 cpp/329-Longest-Increasing-Path-In-A-Matrix.cpp create mode 100644 cpp/33-Search-In-Rotated-Sorted-Array.cpp create mode 100644 cpp/332-Reconstruct-Itinerary.cpp create mode 100644 cpp/338-Counting-Bits.cpp create mode 100644 cpp/347-Top-K-Frequent-Elements.cpp create mode 100644 cpp/355-Design-Twitter.cpp create mode 100644 cpp/36-Valid-Sudoku.cpp create mode 100644 cpp/371-Sum-Of-Two-Integers.cpp create mode 100644 cpp/39-Combination-Sum.cpp create mode 100644 cpp/4-Median-Of-Two-Sorted-Arrays.cpp create mode 100644 cpp/40-Combination-Sum-II.cpp create mode 100644 cpp/416-Partition-Equal-Subset-Sum.cpp create mode 100644 cpp/417-Pacific-Atlantic-Water-Flow.cpp create mode 100644 cpp/42-Trapping-Rain-Water.cpp create mode 100644 cpp/424-Longest-Repeating-Character-Replacement.cpp create mode 100644 cpp/43-Multiply-Strings.cpp create mode 100644 cpp/435-Non-Overlapping-Intervals.cpp create mode 100644 cpp/45-Jump-Game-II.cpp create mode 100644 cpp/46-Permutations.cpp create mode 100644 cpp/48-Rotate-Image.cpp create mode 100644 cpp/49-Group-Anagrams.cpp create mode 100644 cpp/494-Target-Sum.cpp create mode 100644 cpp/5-Longest-Palindrome-Substring.cpp create mode 100644 cpp/50-Pow-X-N.cpp create mode 100644 cpp/51-N-Queens.cpp create mode 100644 cpp/518-Coin-Change-2.cpp create mode 100644 cpp/53-Maximum-Subarray.cpp create mode 100644 cpp/54-Spiral-Matrix.cpp create mode 100644 cpp/543-Diameter-Of-Binary-Tree.cpp create mode 100644 cpp/55-Jump-Game.cpp create mode 100644 cpp/56-Merge-Intervals.cpp create mode 100644 cpp/567-Permutation-In-String.cpp create mode 100644 cpp/57-Insert-Interval.cpp create mode 100644 cpp/572-Subtree-Of-Another-Tree.cpp create mode 100644 cpp/62-Unique-Paths.cpp create mode 100644 cpp/621-Task-Scheduler.cpp create mode 100644 cpp/647-Palindromic-Substrings.cpp create mode 100644 cpp/66-Plus-One.cpp create mode 100644 cpp/684-Redundant-Connection.cpp create mode 100644 cpp/695-Max-Area-Of-Island.cpp create mode 100644 cpp/7-Reverse-Integer.cpp create mode 100644 cpp/70-Climbing-Stairs.cpp create mode 100644 cpp/703-Kth-Largest-Element-In-A-Stream.cpp create mode 100644 cpp/704-Binary-Search.cpp create mode 100644 cpp/72-Edit-Distance.cpp create mode 100644 cpp/73-Set-Matrix-Zeroes.cpp create mode 100644 cpp/739-Daily-Temperatures.cpp create mode 100644 cpp/74-Search-A-2d-Matrix.cpp create mode 100644 cpp/743-Network-Delay-Time.cpp create mode 100644 cpp/746-Min-Cost-Climbing-Stairs.cpp create mode 100644 cpp/76-Minimum-Window-Substring.cpp create mode 100644 cpp/763-Partition-Labels.cpp create mode 100644 cpp/778-Swim-In-Rising-Water.cpp create mode 100644 cpp/78-Subsets.cpp create mode 100644 cpp/787-Cheapest-Flights-Within-K-Stops.cpp create mode 100644 cpp/79-Word-Search.cpp create mode 100644 cpp/84-Largest-Rectangle-In-Histogram.cpp create mode 100644 cpp/846-Hand-Of-Straights.cpp create mode 100644 cpp/853-Car-Fleet.cpp create mode 100644 cpp/875-Koko-Eating-Bananas.cpp create mode 100644 cpp/875-Koko-Eating-Bananas.cpp-Hand-Of-Straights.cpp create mode 100644 cpp/90-Subsets-II.cpp create mode 100644 cpp/91-Decode-Ways.cpp create mode 100644 cpp/953-Alien-Dictionary.cpp create mode 100644 cpp/97-Interleaving-String.cpp create mode 100644 cpp/973-K-Closest-Points-To-Origin.cpp create mode 100644 cpp/98-Validate-Binary-Search-Tree.cpp create mode 100644 cpp/981-Time-Based-Key-Value-Store.cpp create mode 100644 cpp/994-Rotting-Oranges.cpp diff --git a/cpp/1-Two-Sum.cpp b/cpp/1-Two-Sum.cpp new file mode 100644 index 000000000..d70e01dac --- /dev/null +++ b/cpp/1-Two-Sum.cpp @@ -0,0 +1,30 @@ +/* + Given int array & target, return indices of 2 nums that add to target + Ex. nums = [2,7,11,15] & target = 9 -> [0,1], 2 + 7 = 9 + + At each num, calculate complement, if exists in hash map then return + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map m; + vector result; + + for (int i = 0; i < nums.size(); i++) { + int complement = target - nums[i]; + if (m.find(complement) != m.end()) { + result.push_back(m[complement]); + result.push_back(i); + break; + } else { + m.insert({nums[i], i}); + } + } + + return result; + } +}; diff --git a/cpp/10-Regular-Expression-Matching.cpp b/cpp/10-Regular-Expression-Matching.cpp new file mode 100644 index 000000000..e8088e799 --- /dev/null +++ b/cpp/10-Regular-Expression-Matching.cpp @@ -0,0 +1,49 @@ +/* + Given string & pattern, implement RegEx matching + '.' -> matches any single character + '*' -> matches zero or more of the preceding element + Matching should cover the entire input string (not partial) + Ex. s = "aa", p = "a" -> false, "a" doesn't match entire string "aa" + + DFS + memo, 2 choices at a *: either use it, or don't use it + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + bool isMatch(string s, string p) { + return dfs(s, p, 0, 0); + } +private: + map, bool> dp; + + bool dfs(string& s, string& p, int i, int j) { + if (dp.find({i, j}) != dp.end()) { + return dp[{i, j}]; + } + + if (i >= s.size() && j >= p.size()) { + return true; + } + if (j >= p.size()) { + return false; + } + + bool match = i < s.size() && (s[i] == p[j] || p[j] == '.'); + if (j + 1 < p.size() && p[j + 1] == '*') { + // choices: either (1) don't use *, or (2) use * + dp[{i, j}] = dfs(s, p, i, j + 2) || (match && dfs(s, p, i + 1, j)); + return dp[{i, j}]; + } + + if (match) { + dp[{i, j}] = dfs(s, p, i + 1, j + 1); + return dp[{i, j}]; + } + + dp[{i, j}] = false; + return dp[{i, j}]; + } +}; diff --git a/cpp/100-Same-Tree.cpp b/cpp/100-Same-Tree.cpp new file mode 100644 index 000000000..b5843c9e7 --- /dev/null +++ b/cpp/100-Same-Tree.cpp @@ -0,0 +1,36 @@ +/* + Given roots of 2 binary trees, check if they're the same or not (same structure & values) + Ex. p = [1,2,3] q = [1,2,3] -> true, p = [1,2] q = [1,null,2] -> false + + Check: (1) matching nulls, (2) non-matching nulls, (3) non-matching values + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + bool isSameTree(TreeNode* p, TreeNode* q) { + if (p == NULL && q == NULL) { + return true; + } + if (p == NULL || q == NULL) { + return false; + } + if (p->val != q->val) { + return false; + } + return isSameTree(p->left, q->left) && isSameTree(p->right, q->right); + } +}; diff --git a/cpp/102-Binary-Tree-Level-Order-Traversal.cpp b/cpp/102-Binary-Tree-Level-Order-Traversal.cpp new file mode 100644 index 000000000..cacee33ca --- /dev/null +++ b/cpp/102-Binary-Tree-Level-Order-Traversal.cpp @@ -0,0 +1,57 @@ +/* + Given root of binary tree, return level order traversal of its nodes (left to right) + Ex. root = [3,9,20,null,null,15,7] -> [[3],[9,20],[15,7]] + + Standard BFS traversal, at each level, push left & right nodes if they exist to queue + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + vector> levelOrder(TreeNode* root) { + vector> result; + + if (root == NULL) { + return result; + } + + queue q; + q.push(root); + + while (!q.empty()) { + int count = q.size(); + vector curr; + + for (int i = 0; i < count; i++) { + TreeNode* node = q.front(); + q.pop(); + + curr.push_back(node->val); + + if (node->left != NULL) { + q.push(node->left); + } + if (node->right != NULL) { + q.push(node->right); + } + } + + result.push_back(curr); + } + + return result; + } +}; diff --git a/cpp/104-Maximum-Depth-Of-Binary-Tree.cpp b/cpp/104-Maximum-Depth-Of-Binary-Tree.cpp new file mode 100644 index 000000000..75a76f696 --- /dev/null +++ b/cpp/104-Maximum-Depth-Of-Binary-Tree.cpp @@ -0,0 +1,56 @@ +/* + Given root of binary tree, return max depth (# nodes along longest path from root to leaf) + + At every node, max depth is the max depth between its left & right children + 1 + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + int maxDepth(TreeNode* root) { + if (root == NULL) { + return 0; + } + return 1 + max(maxDepth(root->left), maxDepth(root->right)); + } +}; + +// class Solution { +// public: +// int maxDepth(TreeNode* root) { +// if (root == NULL) { +// return 0; +// } +// queue q; +// q.push(root); +// int result = 0; +// while (!q.empty()) { +// int count = q.size(); +// for (int i = 0; i < count; i++) { +// TreeNode* node = q.front(); +// q.pop(); +// if (node->left != NULL) { +// q.push(node->left); +// } +// if (node->right != NULL) { +// q.push(node->right); +// } +// } +// result++; +// } +// return result; +// } +// }; diff --git a/cpp/1046-Last-Stone-Weight.cpp b/cpp/1046-Last-Stone-Weight.cpp new file mode 100644 index 000000000..12c70ccdb --- /dev/null +++ b/cpp/1046-Last-Stone-Weight.cpp @@ -0,0 +1,35 @@ +/* + Given array of stones to smash, return smallest possible weight of last stone + If x == y both stones destroyed, if x != y stone x destroyed, stone y = y - x + Ex. stones = [2,7,4,1,8,1] -> 1, [2,4,1,1,1], [2,1,1,1], [1,1,1], [1] + + Max heap, pop 2 biggest, push back difference until no more 2 elements left + + Time: O(n log n) + Space: O(n) +*/ + +class Solution { +public: + int lastStoneWeight(vector& stones) { + priority_queue pq; + for (int i = 0; i < stones.size(); i++) { + pq.push(stones[i]); + } + + while (pq.size() > 1) { + int y = pq.top(); + pq.pop(); + int x = pq.top(); + pq.pop(); + if (y > x) { + pq.push(y - x); + } + } + + if (pq.empty()) { + return 0; + } + return pq.top(); + } +}; diff --git a/cpp/105-Construct-Binary-Tree-From-Preorder-And-Inorder.cpp b/cpp/105-Construct-Binary-Tree-From-Preorder-And-Inorder.cpp new file mode 100644 index 000000000..b577dc928 --- /dev/null +++ b/cpp/105-Construct-Binary-Tree-From-Preorder-And-Inorder.cpp @@ -0,0 +1,50 @@ +/* + Given 2 integer arrays preorder & inorder, construct & return the binary tree + Ex. preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] -> [3,9,20,null,null,15,7] + + Preorder dictates nodes, inorder dictates subtrees (preorder values, inorder positions) + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + TreeNode* buildTree(vector& preorder, vector& inorder) { + int index = 0; + return build(preorder, inorder, index, 0, inorder.size() - 1); + } +private: + TreeNode* build(vector& preorder, vector& inorder, int& index, int i, int j) { + if (i > j) { + return NULL; + } + + TreeNode* root = new TreeNode(preorder[index]); + + int split = 0; + for (int i = 0; i < inorder.size(); i++) { + if (preorder[index] == inorder[i]) { + split = i; + break; + } + } + index++; + + root->left = build(preorder, inorder, index, i, split - 1); + root->right = build(preorder, inorder, index, split + 1, j); + + return root; + } +}; diff --git a/cpp/11-Container-With-Most-Water.cpp b/cpp/11-Container-With-Most-Water.cpp new file mode 100644 index 000000000..5d5ff435d --- /dev/null +++ b/cpp/11-Container-With-Most-Water.cpp @@ -0,0 +1,33 @@ +/* + Given array of heights, find max water container can store + Ex. height = [1,8,6,2,5,4,8,3,7] -> 49, (8 - 1) x min(8, 7) + + 2 pointers outside in, greedily iterate pointer w/ lower height + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int maxArea(vector& height) { + int i = 0; + int j = height.size() - 1; + + int curr = 0; + int result = 0; + + while (i < j) { + curr = (j - i) * min(height[i], height[j]); + result = max(result, curr); + + if (height[i] <= height[j]) { + i++; + } else { + j--; + } + } + + return result; + } +}; diff --git a/cpp/110-Balanced-Binary-Tree.cpp b/cpp/110-Balanced-Binary-Tree.cpp new file mode 100644 index 000000000..751c3e21f --- /dev/null +++ b/cpp/110-Balanced-Binary-Tree.cpp @@ -0,0 +1,47 @@ +/* + Given binary tree, determine if height-balanced (all left & right subtrees height diff <= 1) + + Check if subtrees are balanced, if so, use their heights to determine further balance + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + bool isBalanced(TreeNode* root) { + int height = 0; + return dfs(root, height); + } +private: + bool dfs(TreeNode* root, int& height) { + if (root == NULL) { + height = -1; + return true; + } + + int left = 0; + int right = 0; + + if (!dfs(root->left, left) || !dfs(root->right, right)) { + return false; + } + if (abs(left - right) > 1) { + return false; + } + + height = 1 + max(left, right); + return true; + } +}; diff --git a/cpp/1143-Longest-Common-Subsequence.cpp b/cpp/1143-Longest-Common-Subsequence.cpp new file mode 100644 index 000000000..43cbe1947 --- /dev/null +++ b/cpp/1143-Longest-Common-Subsequence.cpp @@ -0,0 +1,37 @@ +/* + Given 2 strings, return length of longest common subsequence + Ex. text1 = "abcde", text2 = "ace" -> 3, "ace" is LCS + + j + a c e + a 3 + b 2 --> visualization of below, build DP bottom-up + i c 2 + d 1 + e 1 + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int longestCommonSubsequence(string text1, string text2) { + int m = text1.size(); + int n = text2.size(); + + vector> dp(m + 1, vector(n + 1)); + + for (int i = m - 1; i >= 0; i--) { + for (int j = n - 1; j >= 0; j--) { + if (text1[i] == text2[j]) { + dp[i][j] = 1 + dp[i + 1][j + 1]; + } else { + dp[i][j] = max(dp[i + 1][j], dp[i][j + 1]); + } + } + } + + return dp[0][0]; + } +}; diff --git a/cpp/115-Distinct-Subsequences.cpp b/cpp/115-Distinct-Subsequences.cpp new file mode 100644 index 000000000..bb6d371cb --- /dev/null +++ b/cpp/115-Distinct-Subsequences.cpp @@ -0,0 +1,41 @@ +/* + Given 2 strings s & t: + Return # of distinct subsequences of s which equals t + Ex. s = "rabbbit", t = "rabbit" -> 3, RABBbIT, RAbBBIT, RABbBIT + + DFS + memo, cache on i & j indices to the # of distinct subseq + 2 choices: if chars equal, look at remainder of both s & t + if chars not equal, only look at remainder of s + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int numDistinct(string s, string t) { + return dfs(s, t, 0, 0); + } +private: + // {(i, j) -> # of distinct subsequences} + map, int> dp; + + int dfs(string& s, string& t, int i, int j) { + if (j == t.size()) { + return 1; + } + if (i == s.size()) { + return 0; + } + if (dp.find({i, j}) != dp.end()) { + return dp[{i, j}]; + } + + if (s[i] == t[j]) { + dp[{i, j}] = dfs(s, t, i + 1, j + 1) + dfs(s, t, i + 1, j); + } else { + dp[{i, j}] = dfs(s, t, i + 1, j); + } + return dp[{i, j}]; + } +}; diff --git a/cpp/121-Best-Time-To-Buy-And-Sell-Stock.cpp b/cpp/121-Best-Time-To-Buy-And-Sell-Stock.cpp new file mode 100644 index 000000000..54afd242b --- /dev/null +++ b/cpp/121-Best-Time-To-Buy-And-Sell-Stock.cpp @@ -0,0 +1,24 @@ +/* + Given array prices, return max profit w/ 1 buy & 1 sell + Ex. prices = [7,1,5,3,6,4] -> 5 (buy at $1, sell at $6) + + For each, get diff b/w that & min value before, store max + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int maxProfit(vector& prices) { + int minValue = prices[0]; + int maxDiff = 0; + + for (int i = 1; i < prices.size(); i++) { + minValue = min(minValue, prices[i]); + maxDiff = max(maxDiff, prices[i] - minValue); + } + + return maxDiff; + } +}; diff --git a/cpp/124-Binary-Tree-Maximum-Path-Sum.cpp b/cpp/124-Binary-Tree-Maximum-Path-Sum.cpp new file mode 100644 index 000000000..751da2414 --- /dev/null +++ b/cpp/124-Binary-Tree-Maximum-Path-Sum.cpp @@ -0,0 +1,42 @@ +/* + Given root of binary tree, return max path sum (seq of adj node values added together) + + Path can only have <= 1 split point, assume curPath has it, so return can't split again + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + int maxPathSum(TreeNode* root) { + int maxPath = INT_MIN; + dfs(root, maxPath); + return maxPath; + } +private: + int dfs(TreeNode* root, int& maxPath) { + if (root == NULL) { + return 0; + } + + int left = max(dfs(root->left, maxPath), 0); + int right = max(dfs(root->right, maxPath), 0); + + int curPath = root->val + left + right; + maxPath = max(maxPath, curPath); + + return root->val + max(left, right); + } +}; diff --git a/cpp/125-Valid-Palindrome.cpp b/cpp/125-Valid-Palindrome.cpp new file mode 100644 index 000000000..3f71d0254 --- /dev/null +++ b/cpp/125-Valid-Palindrome.cpp @@ -0,0 +1,33 @@ +/* + Given a string s, return true if it's a palindrome + Ex. s = "A man, a plan, a canal: Panama" -> true + + 2 pointers, outside in, skip non-letters & compare + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + bool isPalindrome(string s) { + int i = 0; + int j = s.size() - 1; + + while (i < j) { + while (!isalnum(s[i]) && i < j) { + i++; + } + while (!isalnum(s[j]) && i < j) { + j--; + } + if (tolower(s[i]) != tolower(s[j])) { + return false; + } + i++; + j--; + } + + return true; + } +}; diff --git a/cpp/127-Word-Ladder.cpp b/cpp/127-Word-Ladder.cpp new file mode 100644 index 000000000..6d698aed2 --- /dev/null +++ b/cpp/127-Word-Ladder.cpp @@ -0,0 +1,55 @@ +/* + Given 2 words & a dictionary, return min # of words to transform b/w them + Ex. begin = "hit", end = "cog", dict = ["hot","dot","dog","lot","log","cog"] -> 5 + "hit" -> "hot" -> "dot" -> "dog" -> "cog" + + BFS, change 1 letter at a time (neighbors), if in dict add to queue, else skip + + Time: O(m^2 x n) -> m = length of each word, n = # of words in input word list + Space: O(m^2 x n) +*/ + +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set dict; + for (int i = 0; i < wordList.size(); i++) { + dict.insert(wordList[i]); + } + + queue q; + q.push(beginWord); + + int result = 1; + + while (!q.empty()) { + int count = q.size(); + + for (int i = 0; i < count; i++) { + string word = q.front(); + q.pop(); + + if (word == endWord) { + return result; + } + dict.erase(word); + + for (int j = 0; j < word.size(); j++) { + char c = word[j]; + for (int k = 0; k < 26; k++) { + word[j] = k + 'a'; + if (dict.find(word) != dict.end()) { + q.push(word); + dict.erase(word); + } + word[j] = c; + } + } + } + + result++; + } + + return 0; + } +}; diff --git a/cpp/128-Longest-Consecutive-Sequence.cpp b/cpp/128-Longest-Consecutive-Sequence.cpp new file mode 100644 index 000000000..bba4acb52 --- /dev/null +++ b/cpp/128-Longest-Consecutive-Sequence.cpp @@ -0,0 +1,29 @@ +/* + Given unsorted array, return length of longest consecutive sequence + Ex. nums = [100,4,200,1,3,2] -> 4, longest is [1,2,3,4] + + Store in hash set, only check for longer seq if it's the beginning + + Time: O(n) + Space: O(n) +*/ + + +class Solution { +public: + int longestConsecutive(vector& nums) { + unordered_sets(nums.begin(), nums.end()); + int longest = 0; + for(auto &n: s){ + //if this is the start of the sequence + if(!s.count(n - 1)){ + int length = 1; + while(s.count(n + length)) + ++length; + longest = max(longest, length); + } + + } + return longest; + } +}; diff --git a/cpp/130-Surrounded-Regions.cpp b/cpp/130-Surrounded-Regions.cpp new file mode 100644 index 000000000..2b665a94e --- /dev/null +++ b/cpp/130-Surrounded-Regions.cpp @@ -0,0 +1,52 @@ +/* + Given a matrix, capture ('X') all regions that are surrounded ('O') + + Distinguish captured vs escaped, 'X' vs 'O' vs 'E' + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + void solve(vector>& board) { + int m = board.size(); + int n = board[0].size(); + + // marking escaped cells along the border + for (int i = 0; i < m; i++) { + dfs(board,i,0,m,n); + dfs(board,i,n-1,m,n); + } + + for (int j = 0; j < n; j++) { + dfs(board,0,j,m,n); + dfs(board,m-1,j,m,n); + } + + // flip cells to correct final states + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + if (board[i][j] == 'E') { + board[i][j] = 'O'; + } + } + } + } +private: + void dfs(vector>& board, int i, int j, int m, int n) { + if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] != 'O') { + return; + } + + board[i][j] = 'E'; + + dfs(board, i - 1, j, m, n); + dfs(board, i + 1, j, m, n); + dfs(board, i, j - 1, m, n); + dfs(board, i, j + 1, m, n); + } +}; diff --git a/cpp/131-Palindrome-Partitioning.cpp b/cpp/131-Palindrome-Partitioning.cpp new file mode 100644 index 000000000..6d4866e7a --- /dev/null +++ b/cpp/131-Palindrome-Partitioning.cpp @@ -0,0 +1,44 @@ +/* + Given a string, partition such that every substring is a palindrome, return all possible ones + Ex. s = "aab" -> [["a","a","b"],["aa","b"]], s = "a" -> [["a"]] + + Generate all possible substrings at idx, if palindrome potential candidate, backtrack after + + Time: O(n x 2^n) + Space: O(n) +*/ + +class Solution { +public: + vector> partition(string s) { + vector curr; + vector> result; + dfs(s, 0, curr, result); + return result; + } +private: + void dfs(string s, int start, vector& curr, vector>& result) { + if (start == s.size()) { + result.push_back(curr); + return; + } + for (int i = start; i < s.size(); i++) { + if (isPalindrome(s, start, i)) { + string str = s.substr(start, i - start + 1); + curr.push_back(str); + dfs(s, i + 1, curr, result); + curr.pop_back(); + } + } + } + bool isPalindrome(string s, int left, int right) { + while (left < right) { + if (s[left] != s[right]) { + return false; + } + left++; + right--; + } + return true; + } +}; diff --git a/cpp/133-Clone-Graph.cpp b/cpp/133-Clone-Graph.cpp new file mode 100644 index 000000000..12e35f0ea --- /dev/null +++ b/cpp/133-Clone-Graph.cpp @@ -0,0 +1,83 @@ +/* + Given ref of a node in connected undirected graph, return deep copy + + Both BFS & DFS work, map original node to its copy + + Time: O(m + n) + Space: O(n) +*/ + +/* +// Definition for a Node. +class Node { +public: + int val; + vector neighbors; + Node() { + val = 0; + neighbors = vector(); + } + Node(int _val) { + val = _val; + neighbors = vector(); + } + Node(int _val, vector _neighbors) { + val = _val; + neighbors = _neighbors; + } +}; +*/ + +// class Solution { +// public: +// Node* cloneGraph(Node* node) { +// if (node == NULL) { +// return NULL; +// } +// if (m.find(node) == m.end()) { +// m[node] = new Node(node->val); +// for (int i = 0; i < node->neighbors.size(); i++) { +// Node* neighbor = node->neighbors[i]; +// m[node]->neighbors.push_back(cloneGraph(neighbor)); +// } +// } +// return m[node]; +// } +// private: +// unordered_map m; +// }; + +class Solution { +public: + Node* cloneGraph(Node* node) { + if (node == NULL) { + return NULL; + } + + Node* copy = new Node(node->val); + m[node] = copy; + + queue q; + q.push(node); + + while (!q.empty()) { + Node* curr = q.front(); + q.pop(); + + for (int i = 0; i < curr->neighbors.size(); i++) { + Node* neighbor = curr->neighbors[i]; + + if (m.find(neighbor) == m.end()) { + m[neighbor] = new Node(neighbor->val); + q.push(neighbor); + } + + m[curr]->neighbors.push_back(m[neighbor]); + } + } + + return copy; + } +private: + unordered_map m; +}; diff --git a/cpp/134-Gas-Station.cpp b/cpp/134-Gas-Station.cpp new file mode 100644 index 000000000..ff4c7468c --- /dev/null +++ b/cpp/134-Gas-Station.cpp @@ -0,0 +1,39 @@ +/* + Gas stations along circular route, return where to start to complete 1 trip + Ex. gas = [1,2,3,4,5] cost = [3,4,5,1,2] -> index 3 (station 4), tank = 4,8,7,6,5 + + At a start station, if total ever becomes negative won't work, try next station + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int canCompleteCircuit(vector& gas, vector& cost) { + int n = gas.size(); + + int totalGas = 0; + int totalCost = 0; + for (int i = 0; i < n; i++) { + totalGas += gas[i]; + totalCost += cost[i]; + } + if (totalGas < totalCost) { + return -1; + } + + int total = 0; + int result = 0; + + for (int i = 0; i < n; i++) { + total += gas[i] - cost[i]; + if (total < 0) { + total = 0; + result = i + 1; + } + } + + return result; + } +}; diff --git a/cpp/136-Single-Number.cpp b/cpp/136-Single-Number.cpp new file mode 100644 index 000000000..e20ac227f --- /dev/null +++ b/cpp/136-Single-Number.cpp @@ -0,0 +1,22 @@ +/* + Given int array, every element appears twice except 1, find it + Ex. nums = [2,2,1] -> 1, nums = [4,1,2,1,2] -> 4 + + a XOR a returns 0, so returns 0 for all except the unique one + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int singleNumber(vector& nums) { + int result = 0; + + for (int i = 0; i < nums.size(); i++) { + result = result ^ nums[i]; + } + + return result; + } +}; diff --git a/cpp/138-Copy-List-With-Random-Pointer.cpp b/cpp/138-Copy-List-With-Random-Pointer.cpp new file mode 100644 index 000000000..e280b11bd --- /dev/null +++ b/cpp/138-Copy-List-With-Random-Pointer.cpp @@ -0,0 +1,101 @@ +/* + Given linked list w/ also a random pointer, construct deep copy + + Hash map {old -> new}, O(n) space + Optimize interweave old and new nodes, O(1) space + A -> A' -> B -> B' -> C -> C', A'.random = A.random.next + + Time: O(n) + Space: O(n) -> can optimize to O(1) +*/ + +/* +// Definition for a Node. +class Node { +public: + int val; + Node* next; + Node* random; + + Node(int _val) { + val = _val; + next = NULL; + random = NULL; + } +}; +*/ + +// class Solution { +// public: +// Node* copyRandomList(Node* head) { +// if (head == NULL) { +// return NULL; +// } +// Node* oldNode = head; +// Node* newNode = new Node(oldNode->val); +// visited[oldNode] = newNode; +// while (oldNode != NULL) { +// newNode->next = getClonedNode(oldNode->next); +// newNode->random = getClonedNode(oldNode->random); +// oldNode = oldNode->next; +// newNode = newNode->next; +// } +// return visited[head]; +// } +// private: +// unordered_map visited; +// Node* getClonedNode(Node* node) { +// if (node == NULL) { +// return NULL; +// } +// if (visited.find(node) != visited.end()) { +// return visited[node]; +// } +// visited[node] = new Node(node->val); +// return visited[node]; +// } +// }; + +class Solution { +public: + Node* copyRandomList(Node* head) { + if (head == NULL) { + return NULL; + } + + Node* ptr = head; + while (ptr != NULL) { + Node* newNode = new Node(ptr->val); + newNode->next = ptr->next; + ptr->next = newNode; + ptr = newNode->next; + } + ptr = head; + + while (ptr != NULL) { + if (ptr->random == NULL) { + ptr->next->random == NULL; + } else { + ptr->next->random = ptr->random->next; + } + ptr = ptr->next->next; + } + + Node* oldPtr = head; + Node* newPtr = head->next; + Node* oldHead = head->next; + + while (oldPtr != NULL) { + oldPtr->next = oldPtr->next->next; + if (newPtr->next == NULL) { + newPtr->next = NULL; + } else { + newPtr->next = newPtr->next->next; + } + oldPtr = oldPtr->next; + newPtr = newPtr->next; + } + + return oldHead; + } +}; diff --git a/cpp/139-Word-Break.cpp b/cpp/139-Word-Break.cpp new file mode 100644 index 000000000..c0613d33e --- /dev/null +++ b/cpp/139-Word-Break.cpp @@ -0,0 +1,37 @@ +/* + Given a string & dictionary, return true if: + Can segment string into 1 or more dictionary words + + DP, at each loop, substring, check if in dict, & store + + Time: O(n^3) + Space: O(n) +*/ + +class Solution { +public: + bool wordBreak(string s, vector& wordDict) { + unordered_set words; + for (int i = 0; i < wordDict.size(); i++) { + words.insert(wordDict[i]); + } + + int n = s.size(); + vector dp(n + 1); + dp[0] = true; + + for (int i = 1; i <= n; i++) { + for (int j = i - 1; j >= 0; j--) { + if (dp[j]) { + string word = s.substr(j, i - j); + if (words.find(word) != words.end()) { + dp[i] = true; + break; + } + } + } + } + + return dp[n]; + } +}; diff --git a/cpp/141-Linked-List-Cycle.cpp b/cpp/141-Linked-List-Cycle.cpp new file mode 100644 index 000000000..1745aacdc --- /dev/null +++ b/cpp/141-Linked-List-Cycle.cpp @@ -0,0 +1,38 @@ +/* + Given head of a linked list, determine if it has a cycle in it + + Slow/fast pointers, if they ever intersect then there's a cycle + + Time: O(n) + Space: O(1) +*/ + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + bool hasCycle(ListNode *head) { + if (head == NULL) { + return false; + } + + ListNode* slow = head; + ListNode* fast = head; + + while (fast->next != NULL && fast->next->next != NULL) { + slow = slow->next; + fast = fast->next->next; + if (slow == fast) { + return true; + } + } + + return false; + } +}; diff --git a/cpp/143-Reorder-List.cpp b/cpp/143-Reorder-List.cpp new file mode 100644 index 000000000..bbd971f32 --- /dev/null +++ b/cpp/143-Reorder-List.cpp @@ -0,0 +1,75 @@ +/* + Given head of linked-list, reorder list alternating outside in + Ex. head = [1,2,3,4] -> [1,4,2,3], head = [1,2,3,4,5] -> [1,5,2,4,3] + + Find middle node, split in half, reverse 2nd half of list, merge + + Time: O(n) + Space: O(1) +*/ + +/** + * 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) {} + * }; + */ +class Solution { +public: + void reorderList(ListNode* head) { + if (head->next == NULL) { + return; + } + + ListNode* prev = NULL; + ListNode* slow = head; + ListNode* fast = head; + + while (fast != NULL && fast->next != NULL) { + prev = slow; + slow = slow->next; + fast = fast->next->next; + } + + prev->next = NULL; + + ListNode* l1 = head; + ListNode* l2 = reverse(slow); + + merge(l1, l2); + } +private: + ListNode* reverse(ListNode* head) { + ListNode* prev = NULL; + ListNode* curr = head; + ListNode* next = curr->next; + + while (curr != NULL) { + next = curr->next; + curr->next = prev; + prev = curr; + curr = next; + } + + return prev; + } + void merge(ListNode* l1, ListNode* l2) { + while (l1 != NULL) { + ListNode* p1 = l1->next; + ListNode* p2 = l2->next; + + l1->next = l2; + if (p1 == NULL) { + break; + } + l2->next = p1; + + l1 = p1; + l2 = p2; + } + } +}; diff --git a/cpp/1448-Count-Good-Nodes-In-Binary-Tree.cpp b/cpp/1448-Count-Good-Nodes-In-Binary-Tree.cpp new file mode 100644 index 000000000..e59e372ad --- /dev/null +++ b/cpp/1448-Count-Good-Nodes-In-Binary-Tree.cpp @@ -0,0 +1,41 @@ +/* + Given binary tree, node is "good" if path from root has no nodes > X, return # of "good" + + Maintain greatest value seen so far on a path, if further node >= this max, "good" node + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + int goodNodes(TreeNode* root) { + int result = 0; + dfs(root, root->val, result); + return result; + } +private: + void dfs(TreeNode* root, int maxSoFar, int& result) { + if (root == NULL) { + return; + } + + if (root->val >= maxSoFar) { + result++; + } + + dfs(root->left, max(maxSoFar, root->val), result); + dfs(root->right, max(maxSoFar, root->val), result); + } +}; diff --git a/cpp/146-Lru-Cache.cpp b/cpp/146-Lru-Cache.cpp new file mode 100644 index 000000000..1cd5e456b --- /dev/null +++ b/cpp/146-Lru-Cache.cpp @@ -0,0 +1,94 @@ +/* + Design data structure that follows constraints of an LRU cache + + Hash map + doubly linked list, left = LRU, right = MRU + get: update to MRU, put: update to MRU, remove LRU if full + + Time: O(1) + Space: O(capacity) +*/ + +class Node { +public: + int k; + int val; + Node* prev; + Node* next; + + Node(int key, int value) { + k = key; + val = value; + prev = NULL; + next = NULL; + } +}; + +class LRUCache { +public: + LRUCache(int capacity) { + cap = capacity; + + left = new Node(0, 0); + right = new Node(0, 0); + + left->next = right; + right->prev = left; + } + + int get(int key) { + if (cache.find(key) != cache.end()) { + remove(cache[key]); + insert(cache[key]); + return cache[key]->val; + } + return -1; + } + + void put(int key, int value) { + if (cache.find(key) != cache.end()) { + remove(cache[key]); + } + cache[key] = new Node(key, value); + insert(cache[key]); + + if (cache.size() > cap) { + // remove from list & delete LRU from map + Node* lru = left->next; + remove(lru); + cache.erase(lru->k); + } + } +private: + int cap; + unordered_map cache; // {key -> node} + Node* left; + Node* right; + + // remove node from list + void remove(Node* node) { + Node* prev = node->prev; + Node* next = node->next; + + prev->next = next; + next->prev = prev; + } + + // insert node at right + void insert(Node* node) { + Node* prev = right->prev; + Node* next = right; + + prev->next = node; + next->prev = node; + + node->prev = prev; + node->next = next; + } +}; + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache* obj = new LRUCache(capacity); + * int param_1 = obj->get(key); + * obj->put(key,value); + */ diff --git a/cpp/15-3sum.cpp b/cpp/15-3sum.cpp new file mode 100644 index 000000000..654a8b07c --- /dev/null +++ b/cpp/15-3sum.cpp @@ -0,0 +1,59 @@ +/* + Given int array, return all unique triplets that sum to 0 + Ex. nums = [-1,0,1,2,-1,-4] -> [[-1,-1,2],[-1,0,1]] + + Sort, for each i, have j & k go outside in, check for 0 sums + + Time: O(n^2) + Space: O(n) +*/ + +class Solution { +public: + vector> threeSum(vector& nums) { + vector> result; + + int n = nums.size(); + if (n < 3) { + return result; + } + + sort(nums.begin(), nums.end()); + + for (int i = 0; i < n - 2; i++) { + if (nums[i] > 0) { + break; + } + if (i > 0 && nums[i - 1] == nums[i]) { + continue; + } + + int j = i + 1; + int k = n - 1; + + while (j < k) { + int sum = nums[i] + nums[j] + nums[k]; + + if (sum < 0) { + j++; + } else if (sum > 0) { + k--; + } else { + result.push_back({nums[i], nums[j], nums[k]}); + + while (j < k && nums[j] == nums[j + 1]) { + j++; + } + j++; + + while (j < k && nums[k - 1] == nums[k]) { + k--; + } + k--; + } + } + } + + return result; + } +}; diff --git a/cpp/150-Evaluate-Reverse-Polish-Notation.cpp b/cpp/150-Evaluate-Reverse-Polish-Notation.cpp new file mode 100644 index 000000000..5f86685df --- /dev/null +++ b/cpp/150-Evaluate-Reverse-Polish-Notation.cpp @@ -0,0 +1,43 @@ +/* + Evaluate RPN, valid operators: +, -, *, / + + Stack, if num push, if operator apply to top 2 nums + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + int evalRPN(vector& tokens) { + stack stk; + + for (int i = 0; i < tokens.size(); i++) { + string token = tokens[i]; + + if (token.size() > 1 || isdigit(token[0])) { + stk.push(stoi(token)); + continue; + } + + int num2 = stk.top(); + stk.pop(); + int num1 = stk.top(); + stk.pop(); + + int result = 0; + if (token == "+") { + result = num1 + num2; + } else if (token == "-") { + result = num1 - num2; + } else if (token == "*") { + result = num1 * num2; + } else { + result = num1 / num2; + } + stk.push(result); + } + + return stk.top(); + } +}; diff --git a/cpp/152-Maximum-Product-Subarray.cpp b/cpp/152-Maximum-Product-Subarray.cpp new file mode 100644 index 000000000..6ebf07383 --- /dev/null +++ b/cpp/152-Maximum-Product-Subarray.cpp @@ -0,0 +1,30 @@ +/* + Given int array, find contiguous subarray w/ max product, return product + Ex. nums = [2,3,-2,4] -> output = 6, [2,3] has max product at 6 + + Think wrt combo chains, if +'ve ints good, but if 0's bad, if -'ve depends + 0's force reset, -'ve could sway the best ans, therefore track currMax & currMin + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int maxProduct(vector& nums) { + int currMax = nums[0]; + int currMin = nums[0]; + int result = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + int temp = currMax; + + currMax = max(max(currMax * nums[i], currMin * nums[i]), nums[i]); + currMin = min(min(currMin * nums[i], temp * nums[i]), nums[i]); + + result = max(result, currMax); + } + + return result; + } +}; diff --git a/cpp/153-Find-Minimum-In-Rotated-Sorted-Array.cpp b/cpp/153-Find-Minimum-In-Rotated-Sorted-Array.cpp new file mode 100644 index 000000000..57ce29bbd --- /dev/null +++ b/cpp/153-Find-Minimum-In-Rotated-Sorted-Array.cpp @@ -0,0 +1,36 @@ +/* + Given sorted array after some rotation, find min value + Ex. nums = [3,4,5,1,2] -> 1, nums = [4,5,6,7,0,1,2] -> 0 + + Binary search + ensuring we never disqualify possible min value + + Time: O(log n) + Space: O(1) +*/ + +class Solution { +public: + int findMin(vector& nums) { + int low = 0; + int high = nums.size() - 1; + + // not low <= high since not searching for target + while (low < high) { + int mid = low + (high - low) / 2; + // ex. [3,4,5,6,7,8,9,1,2], mid = 4, high = 8 + // nums[mid] > nums[high], min must be right + if (nums[mid] > nums[high]) { + // never consider mid bc know for sure not min + low = mid + 1; + // ex. [8,9,1,2,3,4,5,6,7], mid = 4, high = 8 + // nums[mid] <= nums[right], min must be left + } else { + // consider mid still bc could be min + high = mid; + } + } + + // low lands on correct value, never disqualified mins + return nums[low]; + } +}; diff --git a/cpp/155-Min-Stack.cpp b/cpp/155-Min-Stack.cpp new file mode 100644 index 000000000..dfe073550 --- /dev/null +++ b/cpp/155-Min-Stack.cpp @@ -0,0 +1,55 @@ +/* + Design stack that supports push, pop, top, & retriving min element + + 2 stacks, 1 normal & 1 monotonic decr, only push if lower than top + + Time: O(1) + Space: O(n) +*/ + +class MinStack { +public: + MinStack() { + + } + + void push(int val) { + stk.push(val); + + if (minStk.empty() || val < minStk.top().first) { + minStk.push({val, 1}); + } else if (val == minStk.top().first) { + minStk.top().second++; + } + } + + void pop() { + if (stk.top() == minStk.top().first) { + minStk.top().second--; + if (minStk.top().second == 0) { + minStk.pop(); + } + } + stk.pop(); + } + + int top() { + return stk.top(); + } + + int getMin() { + return minStk.top().first; + } +private: + stack stk; + stack> minStk; +}; + +/** + * Your MinStack object will be instantiated and called as such: + * MinStack* obj = new MinStack(); + * obj->push(val); + * obj->pop(); + * int param_3 = obj->top(); + * int param_4 = obj->getMin(); + */ diff --git a/cpp/1584-Min-Cost-To-Connect-All-Points.cpp b/cpp/1584-Min-Cost-To-Connect-All-Points.cpp new file mode 100644 index 000000000..7beb444fb --- /dev/null +++ b/cpp/1584-Min-Cost-To-Connect-All-Points.cpp @@ -0,0 +1,54 @@ +/* + Given array of points, return min cost to connect all points + All points have 1 path b/w them, cost is Manhattan distance + + MST problem, Prim's, greedily pick node not in MST & has smallest edge cost + Add to MST, & for all its neighbors, try to update min dist values, repeat + + Time: O(n^2) + Space: O(n) +*/ + +class Solution { +public: + int minCostConnectPoints(vector>& points) { + int n = points.size(); + + int edgesUsed = 0; + // track visited nodes + vector inMST(n); + vector minDist(n, INT_MAX); + minDist[0] = 0; + + int result = 0; + + while (edgesUsed < n) { + int currMinEdge = INT_MAX; + int currNode = -1; + + // greedily pick lowest cost node not in MST + for (int i = 0; i < n; i++) { + if (!inMST[i] && currMinEdge > minDist[i]) { + currMinEdge = minDist[i]; + currNode = i; + } + } + + result += currMinEdge; + edgesUsed++; + inMST[currNode] = true; + + // update adj nodes of curr node + for (int i = 0; i < n; i++) { + int cost = abs(points[currNode][0] - points[i][0]) + + abs(points[currNode][1] - points[i][1]); + + if (!inMST[i] && minDist[i] > cost) { + minDist[i] = cost; + } + } + } + + return result; + } +}; diff --git a/cpp/167-Two-Sum-II.cpp b/cpp/167-Two-Sum-II.cpp new file mode 100644 index 000000000..10992b30d --- /dev/null +++ b/cpp/167-Two-Sum-II.cpp @@ -0,0 +1,34 @@ +/* + Given a 1-indexed sorted int array & target: + Return indices (added by 1) of 2 nums that add to target + + 2 pointers, outside in, iterate i/j if sum is too low/high + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + vector twoSum(vector& numbers, int target) { + int i = 0; + int j = numbers.size() - 1; + + vector result; + + while (i < j) { + int sum = numbers[i] + numbers[j]; + if (sum < target) { + i++; + } else if (sum > target) { + j--; + } else { + result.push_back(i + 1); + result.push_back(j + 1); + break; + } + } + + return result; + } +}; diff --git a/cpp/17-Letter-Combinations-Phone-Number.cpp b/cpp/17-Letter-Combinations-Phone-Number.cpp new file mode 100644 index 000000000..e2e87dcf5 --- /dev/null +++ b/cpp/17-Letter-Combinations-Phone-Number.cpp @@ -0,0 +1,47 @@ +/* + Given cell phone pad, return all possible letter combos that the number could represent + Ex. digits = "23" -> ["ad","ae","af","bd","be","bf","cd","ce","cf"] + + Hash map all digits to letters, add 1 letter at a time for each digit, then backtrack undo + + Time: O(n x 4^n) + Space: O(n x 4^n) +*/ + +class Solution { +public: + vector letterCombinations(string digits) { + if (digits.empty()) { + return {}; + } + + unordered_map m = { + {'2', "abc"}, + {'3', "def"}, + {'4', "ghi"}, + {'5', "jkl"}, + {'6', "mno"}, + {'7', "pqrs"}, + {'8', "tuv"}, + {'9', "wxyz"} + }; + string curr = ""; + vector result; + + dfs(digits, 0, m, curr, result); + return result; + } +private: + void dfs(string digits, int index, unordered_map& m, string& curr, vector& result) { + if (index == digits.size()) { + result.push_back(curr); + return; + } + string str = m[digits[index]]; + for (int i = 0; i < str.size(); i++) { + curr.push_back(str[i]); + dfs(digits, index + 1, m, curr, result); + curr.pop_back(); + } + } +}; diff --git a/cpp/1851-Minimum-Interval-To-Include-Each-Query.cpp b/cpp/1851-Minimum-Interval-To-Include-Each-Query.cpp new file mode 100644 index 000000000..1ef415eda --- /dev/null +++ b/cpp/1851-Minimum-Interval-To-Include-Each-Query.cpp @@ -0,0 +1,54 @@ +/* + Given intervals array & queries array, ans to a query is min interval containing it + Ex. intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5] -> [3,3,1,4] + + Min heap & sort by size of intervals, top will be min size, + + Time: O(n log n + q log q) -> n = number of intervals, q = number of queries + Space: O(n + q) +*/ + +class Solution { +public: + vector minInterval(vector>& intervals, vector& queries) { + vector sortedQueries = queries; + + // [size of interval, end of interval] + priority_queue, vector>, greater>> pq; + // {query -> size of interval} + unordered_map m; + + // also need only valid intervals so sort by start time & sort queries + sort(intervals.begin(), intervals.end()); + sort(sortedQueries.begin(), sortedQueries.end()); + + vector result; + + int i = 0; + for (int j = 0; j < sortedQueries.size(); j++) { + int query = sortedQueries[j]; + + while (i < intervals.size() && intervals[i][0] <= query) { + int left = intervals[i][0]; + int right = intervals[i][1]; + pq.push({right - left + 1, right}); + i++; + } + + while (!pq.empty() && pq.top().second < query) { + pq.pop(); + } + + if (!pq.empty()) { + m[query] = pq.top().first; + } else { + m[query] = -1; + } + } + + for (int j = 0; j < queries.size(); j++) { + result.push_back(m[queries[j]]); + } + return result; + } +}; diff --git a/cpp/1899-Merge-Triplets-To-Form-Target-Triplet.cpp b/cpp/1899-Merge-Triplets-To-Form-Target-Triplet.cpp new file mode 100644 index 000000000..326404d17 --- /dev/null +++ b/cpp/1899-Merge-Triplets-To-Form-Target-Triplet.cpp @@ -0,0 +1,30 @@ +/* + Update: [max(ai,aj), max(bi,bj), max(ci,cj)], return if possible to obtain target + Ex. triplets = [[2,5,3],[1,8,4],[1,7,5]] target = [2,7,5] -> true, update 1st/3rd + + Skip all "bad" triplets (can never become target), if match add to "good" set + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + bool mergeTriplets(vector>& triplets, vector& target) { + unordered_set s; + + for (int i = 0; i < triplets.size(); i++) { + if (triplets[i][0] > target[0] || triplets[i][1] > target[1] || triplets[i][2] > target[2]) { + continue; + } + + for (int j = 0; j < 3; j++) { + if (triplets[i][j] == target[j]) { + s.insert(j); + } + } + } + + return s.size() == 3; + } +}; diff --git a/cpp/19-Remove-Nth-Node-From-End-Of-List.cpp b/cpp/19-Remove-Nth-Node-From-End-Of-List.cpp new file mode 100644 index 000000000..af139e8e0 --- /dev/null +++ b/cpp/19-Remove-Nth-Node-From-End-Of-List.cpp @@ -0,0 +1,48 @@ +/* + Given head of a linked list, remove nth node from end of list + Ex. head = [1,2,3,4,5], n = 2 -> [1,2,3,5] + + Create 2 pointers "n" apart, iterate until end, will be at nth + + Time: O(n) + Space: O(1) +*/ + +/** + * 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) {} + * }; + */ +class Solution { +public: + ListNode* removeNthFromEnd(ListNode* head, int n) { + if (head->next == NULL) { + return NULL; + } + + ListNode* slow = head; + ListNode* fast = head; + + while (n > 0) { + fast = fast->next; + n--; + } + + if (fast == NULL) { + return head->next; + } + + while (fast->next != NULL) { + slow = slow->next; + fast = fast->next; + } + + slow->next = slow->next->next; + return head; + } +}; diff --git a/cpp/190-Reverse-Bits.cpp b/cpp/190-Reverse-Bits.cpp new file mode 100644 index 000000000..3eb0e05d7 --- /dev/null +++ b/cpp/190-Reverse-Bits.cpp @@ -0,0 +1,24 @@ +/* + Reverse bits of a given integer + Ex. n = 10011100 -> 00111001 = 57 + + Shift into result & shift out of n + + Time: O(1) + Space: O(1) +*/ + +class Solution { +public: + uint32_t reverseBits(uint32_t n) { + uint32_t result = 0; + + for (int i = 0; i < 32; i++) { + result <<= 1; + result |= n & 1; + n >>= 1; + } + + return result; + } +}; diff --git a/cpp/191-Number-Of-1-Bits.cpp b/cpp/191-Number-Of-1-Bits.cpp new file mode 100644 index 000000000..9d91bf039 --- /dev/null +++ b/cpp/191-Number-Of-1-Bits.cpp @@ -0,0 +1,27 @@ +/* + Return number of '1' bits in an int + Ex. n = 00001011 -> 3 + + Simply count bit-by-bit & shift it off + + Time: O(1) + Space: O(1) +*/ + +class Solution { +public: + int hammingWeight(uint32_t n) { + int bit = 0; + int result = 0; + + while (n != 0) { + bit = n & 1; + if (bit == 1) { + result++; + } + n = n >> 1; + } + + return result; + } +}; diff --git a/cpp/198-House-Robber.cpp b/cpp/198-House-Robber.cpp new file mode 100644 index 000000000..e7c3c9030 --- /dev/null +++ b/cpp/198-House-Robber.cpp @@ -0,0 +1,27 @@ +/* + Given int array, return max amount can rob (can't rob adjacent houses) + Ex. nums = [1,2,3,1] -> 4, rob house 1 then house 3: 1 + 3 = 4 + + Recursion w/ memoization -> DP, rob either 2 away + here, or 1 away + Recurrence relation: robFrom[i] = max(robFrom[i-2] + nums[i], robFrom[i-1]) + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int rob(vector& nums) { + int prev = 0; + int curr = 0; + int next = 0; + + for (int i = 0; i < nums.size(); i++) { + next = max(prev + nums[i], curr); + prev = curr; + curr = next; + } + + return curr; + } +}; diff --git a/cpp/199-Binary-Tree-Right-Side-View.cpp b/cpp/199-Binary-Tree-Right-Side-View.cpp new file mode 100644 index 000000000..2b68815ab --- /dev/null +++ b/cpp/199-Binary-Tree-Right-Side-View.cpp @@ -0,0 +1,55 @@ +/* + Given root of binary tree, return values that can only be seen from the right side + + BFS traversal, push right first before left, store only first value + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + vector rightSideView(TreeNode* root) { + if (root == NULL) { + return {}; + } + + queue q; + q.push(root); + + vector result; + + while (!q.empty()) { + int count = q.size(); + + for (int i = count; i > 0; i--) { + TreeNode* node = q.front(); + q.pop(); + + if (i == count) { + result.push_back(node->val); + } + + if (node->right != NULL) { + q.push(node->right); + } + if (node->left != NULL) { + q.push(node->left); + } + } + } + + return result; + } +}; diff --git a/cpp/2-Add-Two-Numbers.cpp b/cpp/2-Add-Two-Numbers.cpp new file mode 100644 index 000000000..4d8e96d34 --- /dev/null +++ b/cpp/2-Add-Two-Numbers.cpp @@ -0,0 +1,53 @@ +/* + Given 2 linked lists, digits stored in reverse order, add them + Ex. l1 = [2,4,3] l2 = [5,6,4] -> [7,0,8] (342 + 465 = 807) + + Sum digit-by-digit + carry, handle if one list becomes null + + Time: O(max(m, n)) + Space: O(max(m, n)) +*/ + +/** + * 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) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + ListNode* dummy = new ListNode(); + + ListNode* curr = dummy; + int carry = 0; + + while (l1 != NULL || l2 != NULL) { + int val1 = (l1 != NULL) ? l1->val : 0; + int val2 = (l2 != NULL) ? l2->val : 0; + + int sum = val1 + val2 + carry; + carry = sum / 10; + + curr->next = new ListNode(sum % 10); + curr = curr->next; + + if (l1 != NULL) { + l1 = l1->next; + } + if (l2 != NULL) { + l2 = l2->next; + } + } + + if (carry == 1) { + curr->next = new ListNode(1); + } + + return dummy->next; + } +}; diff --git a/cpp/20-Valid-Parentheses.cpp b/cpp/20-Valid-Parentheses.cpp new file mode 100644 index 000000000..671df220a --- /dev/null +++ b/cpp/20-Valid-Parentheses.cpp @@ -0,0 +1,41 @@ +/* + Given s w/ '(, ), {, }, [, ]', determine if valid + Ex. s = "()[]{}" -> true, s = "(]" -> false + + Stack of opens, check for matching closes & validity + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + bool isValid(string s) { + stack open; + + for (int i = 0; i < s.size(); i++) { + if (s[i] == ')' || s[i] == '}' || s[i] == ']') { + if (open.empty()) { + return false; + } + if (s[i] == ')' && open.top() != '(') { + return false; + } + if (s[i] == '}' && open.top() != '{') { + return false; + } + if (s[i] == ']' && open.top() != '[') { + return false; + } + open.pop(); + } else { + open.push(s[i]); + } + } + + if (!open.empty()) { + return false; + } + return true; + } +}; diff --git a/cpp/20-Valid-Parenthesis-String.cpp b/cpp/20-Valid-Parenthesis-String.cpp new file mode 100644 index 000000000..f01fb9c82 --- /dev/null +++ b/cpp/20-Valid-Parenthesis-String.cpp @@ -0,0 +1,43 @@ +/* + Given s containing '(', ')', or '*', determine if valid + Ex. s = "()" -> true, s = "(*)" -> true, s = "(*))" -> true + + Brute force: try both possibilities for each asterisk + Optimal: greedy, "balance", track min/max lefts + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + bool checkValidString(string s) { + int leftMin = 0; + int leftMax = 0; + + for (int i = 0; i < s.size(); i++) { + if (s[i] == '(') { + leftMin++; + leftMax++; + } else if (s[i] == ')') { + leftMin--; + leftMax--; + } else { + leftMin--; + leftMax++; + } + if (leftMax < 0) { + return false; + } + // ex. s = "(*)(" + if (leftMin < 0) { + leftMin = 0; + } + } + + if (leftMin == 0) { + return true; + } + return false; + } +}; diff --git a/cpp/200-Number-Of-Islands.cpp b/cpp/200-Number-Of-Islands.cpp new file mode 100644 index 000000000..6a1df18ac --- /dev/null +++ b/cpp/200-Number-Of-Islands.cpp @@ -0,0 +1,41 @@ +/* + Given grid where '1' is land & '0' is water, return # of islands + + DFS, set visited land to '0' to not visit it again, count islands + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int numIslands(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + + int result = 0; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { + dfs(grid, i, j, m, n); + result++; + } + } + } + + return result; + } +private: + void dfs(vector>& grid, int i, int j, int m, int n) { + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == '0') { + return; + } + grid[i][j] = '0'; + + dfs(grid, i - 1, j, m, n); + dfs(grid, i + 1, j, m, n); + dfs(grid, i, j - 1, m, n); + dfs(grid, i, j + 1, m, n); + } +}; diff --git a/cpp/2013-Detect-Squares.cpp b/cpp/2013-Detect-Squares.cpp new file mode 100644 index 000000000..641a9d745 --- /dev/null +++ b/cpp/2013-Detect-Squares.cpp @@ -0,0 +1,53 @@ +/* + Given stream of points, add new points, return count of squares + + Find diagonals, if exists then forms a square, loop thru all points + + Time: O(1) add O(n^2) count -> n = number of points + Space: O(n) +*/ + +class DetectSquares { +public: + DetectSquares() { + + } + + void add(vector point) { + points[point[0]][point[1]]++; + } + + int count(vector point) { + int x1 = point[0]; + int y1 = point[1]; + + int result = 0; + + for (auto x = points.begin(); x != points.end(); x++) { + unordered_map yPoints = x->second; + for (auto y = yPoints.begin(); y != yPoints.end(); y++) { + int x3 = x->first; + int y3 = y->first; + + // skip points on same x-axis or y-axis + if (abs(x3 - x1) == 0 || abs(x3 - x1) != abs(y3 - y1)) { + continue; + } + + result += points[x3][y3] * points[x1][y3] * points[x3][y1]; + } + } + + return result; + } +private: + // {x -> {y -> count}} + unordered_map> points; +}; + +/** + * Your DetectSquares object will be instantiated and called as such: + * DetectSquares* obj = new DetectSquares(); + * obj->add(point); + * int param_2 = obj->count(point); + */ diff --git a/cpp/202-Happy-Number.cpp b/cpp/202-Happy-Number.cpp new file mode 100644 index 000000000..a0c78b1dc --- /dev/null +++ b/cpp/202-Happy-Number.cpp @@ -0,0 +1,39 @@ +/* + Given num, replace by sum of squares of its digits + Repeat until 1 or endless loop, determine if ends in 1 + Ex. n = 19 -> true, 1^2 + 9^2 = 82, 8^2 + 2^2 = 68 ... 1 + + Detect cycle w/ slow/fast pointer technique + If happy will eventually be 1, else pointers will meet + + Time: O(log n) + Space: O(1) +*/ + +class Solution { +public: + bool isHappy(int n) { + int slow = n; + int fast = getNext(n); + + while (slow != fast && fast != 1) { + slow = getNext(slow); + fast = getNext(getNext(fast)); + } + + if (fast == 1) { + return true; + } + return false; + } +private: + int getNext(int n) { + int sum = 0; + while (n > 0) { + int digit = n % 10; + n /= 10; + sum += pow(digit, 2); + } + return sum; + } +}; diff --git a/cpp/206-Reverse-Linked-List.cpp b/cpp/206-Reverse-Linked-List.cpp new file mode 100644 index 000000000..1d97dff75 --- /dev/null +++ b/cpp/206-Reverse-Linked-List.cpp @@ -0,0 +1,41 @@ +/* + Given the head of a singly linked list, reverse list & return + Ex. head = [1,2,3,4,5] -> [5,4,3,2,1], head = [1,2] -> [2,1] + + Maintain prev, curr, & next pointers, iterate thru & reverse + + Time: O(n) + Space: O(1) +*/ + +/** + * 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) {} + * }; + */ +class Solution { +public: + ListNode* reverseList(ListNode* head) { + if (head == NULL || head->next == NULL) { + return head; + } + + ListNode* prev = NULL; + ListNode* curr = head; + ListNode* next = curr->next; + + while (curr != NULL) { + next = curr->next; + curr->next = prev; + prev = curr; + curr = next; + } + + return prev; + } +}; diff --git a/cpp/207-Course-Schedule.cpp b/cpp/207-Course-Schedule.cpp new file mode 100644 index 000000000..3df974445 --- /dev/null +++ b/cpp/207-Course-Schedule.cpp @@ -0,0 +1,48 @@ +/* + Courses & prerequisites, return true if can finish all courses + Ex. numCourses = 2, prerequisites = [[1,0]] -> true + + All courses can be completed if there's no cycle (visit already visited) + + Time: O(V + E) + Space: O(V + E) +*/ + +class Solution { +public: + bool canFinish(int numCourses, vector>& prerequisites) { + // map each course to prereq list + unordered_map> m; + for (int i = 0; i < prerequisites.size(); i++) { + m[prerequisites[i][0]].push_back(prerequisites[i][1]); + } + // all courses along current DFS path + unordered_set visited; + + for (int course = 0; course < numCourses; course++) { + if (!dfs(course, m, visited)) { + return false; + } + } + return true; + } +private: + bool dfs(int course, unordered_map>& m, unordered_set& visited) { + if (visited.find(course) != visited.end()) { + return false; + } + if (m[course].empty()) { + return true; + } + visited.insert(course); + for (int i = 0; i < m[course].size(); i++) { + int nextCourse = m[course][i]; + if (!dfs(nextCourse, m, visited)) { + return false; + } + } + m[course].clear(); + visited.erase(course); + return true; + } +}; diff --git a/cpp/208-Implement-Trie-Prefix-Tree.cpp b/cpp/208-Implement-Trie-Prefix-Tree.cpp new file mode 100644 index 000000000..cc8cbefa9 --- /dev/null +++ b/cpp/208-Implement-Trie-Prefix-Tree.cpp @@ -0,0 +1,83 @@ +/* + Implement trie (store/retrieve keys in dataset of strings) + + Each node contains pointer to next letter & is word flag + + Time: O(n) insert, O(n) search, O(n) startsWith + Space: O(n) insert, O(1) search, O(1) startsWith +*/ + +class TrieNode { +public: + TrieNode* children[26]; + bool isWord; + + TrieNode() { + for (int i = 0; i < 26; i++) { + children[i] = NULL; + } + isWord = false; + } +}; + +class Trie { +public: + Trie() { + root = new TrieNode(); + } + + void insert(string word) { + TrieNode* node = root; + int curr = 0; + + for (int i = 0; i < word.size(); i++) { + curr = word[i] - 'a'; + if (node->children[curr] == NULL) { + node->children[curr] = new TrieNode(); + } + node = node->children[curr]; + } + + node->isWord = true; + } + + bool search(string word) { + TrieNode* node = root; + int curr = 0; + + for (int i = 0; i < word.size(); i++) { + curr = word[i] - 'a'; + if (node->children[curr] == NULL) { + return false; + } + node = node->children[curr]; + } + + return node->isWord; + } + + bool startsWith(string prefix) { + TrieNode* node = root; + int curr = 0; + + for (int i = 0; i < prefix.size(); i++) { + curr = prefix[i] - 'a'; + if (node->children[curr] == NULL) { + return false; + } + node = node->children[curr]; + } + + return true; + } +private: + TrieNode* root; +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ diff --git a/cpp/21-Merge-Two-Sorted-Lists.cpp b/cpp/21-Merge-Two-Sorted-Lists.cpp new file mode 100644 index 000000000..febb22345 --- /dev/null +++ b/cpp/21-Merge-Two-Sorted-Lists.cpp @@ -0,0 +1,63 @@ +/* + Given heads of 2 sorted linked lists, merge into 1 sorted list + Ex. list1 = [1,2,4], list2 = [1,3,4] -> [1,1,2,3,4,4] + + Create curr pointer, iterate thru, choose next to be lower one + + Time: O(m + n) + Space: O(1) +*/ + +/** + * 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) {} + * }; + */ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { + if (list1 == NULL && list2 == NULL) { + return NULL; + } + if (list1 == NULL) { + return list2; + } + if (list2 == NULL) { + return list1; + } + + ListNode* head = NULL; + if (list1->val <= list2->val) { + head = list1; + list1 = list1->next; + } else { + head = list2; + list2 = list2->next; + } + ListNode* curr = head; + + while (list1 != NULL && list2 != NULL) { + if (list1->val <= list2->val) { + curr->next = list1; + list1 = list1->next; + } else { + curr->next = list2; + list2 = list2->next; + } + curr = curr->next; + } + + if (list1 == NULL) { + curr->next = list2; + } else { + curr->next = list1; + } + + return head; + } +}; diff --git a/cpp/210-Course-Schedule-II.cpp b/cpp/210-Course-Schedule-II.cpp new file mode 100644 index 000000000..763d68a08 --- /dev/null +++ b/cpp/210-Course-Schedule-II.cpp @@ -0,0 +1,56 @@ +/* + Courses & prerequisites, return ordering of courses to take to finish all courses + Ex. numCourses = 2, prerequisites = [[1,0]] -> [0,1], take course 0 then 1 + + All courses can be completed if there's no cycle, check for cycles + + Time: O(V + E) + Space: O(V + E) +*/ + +class Solution { +public: + vector findOrder(int numCourses, vector>& prerequisites) { + unordered_map> m; + // build adjacency list of prereqs + for (int i = 0; i < prerequisites.size(); i++) { + m[prerequisites[i][0]].push_back(prerequisites[i][1]); + } + unordered_set visit; + unordered_set cycle; + + vector result; + for (int course = 0; course < numCourses; course++) { + if (!dfs(course, m, visit, cycle, result)) { + return {}; + } + } + return result; + } +private: + // a course has 3 possible states: + // visited -> course added to result + // visiting -> course not added to result, but added to cycle + // unvisited -> course not added to result or cycle + bool dfs(int course, unordered_map>& m, unordered_set& visit, + unordered_set& cycle, vector& result) { + + if (cycle.find(course) != cycle.end()) { + return false; + } + if (visit.find(course) != visit.end()) { + return true; + } + cycle.insert(course); + for (int i = 0; i < m[course].size(); i++) { + int nextCourse = m[course][i]; + if (!dfs(nextCourse, m, visit, cycle, result)) { + return false; + } + } + cycle.erase(course); + visit.insert(course); + result.push_back(course); + return true; + } +}; diff --git a/cpp/211-Design-Add-And-Search-Words-Data-Structure.cpp b/cpp/211-Design-Add-And-Search-Words-Data-Structure.cpp new file mode 100644 index 000000000..71a1d4def --- /dev/null +++ b/cpp/211-Design-Add-And-Search-Words-Data-Structure.cpp @@ -0,0 +1,75 @@ +/* + Design add & search words data structure + + Implement trie, handle wildcards: traverse all children & search substrings + + Time: O(m x 26^n) -> m = # of words, n = length of words + Space: O(n) +*/ + +class TrieNode { +public: + TrieNode* children[26]; + bool isWord; + + TrieNode() { + for (int i = 0; i < 26; i++) { + children[i] = NULL; + } + isWord = false; + } +}; + +class WordDictionary { +public: + WordDictionary() { + root = new TrieNode(); + } + + void addWord(string word) { + TrieNode* node = root; + int curr = 0; + + for (int i = 0; i < word.size(); i++) { + curr = word[i] - 'a'; + if (node->children[curr] == NULL) { + node->children[curr] = new TrieNode(); + } + node = node->children[curr]; + } + + node->isWord = true; + } + + bool search(string word) { + TrieNode* node = root; + return searchInNode(word, 0, node); + } +private: + TrieNode* root; + + bool searchInNode(string& word, int i, TrieNode* node) { + if (node == NULL) { + return false; + } + if (i == word.size()) { + return node->isWord; + } + if (word[i] != '.') { + return searchInNode(word, i + 1, node->children[word[i] - 'a']); + } + for (int j = 0; j < 26; j++) { + if (searchInNode(word, i + 1, node->children[j])) { + return true; + } + } + return false; + } +}; + +/** + * Your WordDictionary object will be instantiated and called as such: + * WordDictionary* obj = new WordDictionary(); + * obj->addWord(word); + * bool param_2 = obj->search(word); + */ diff --git a/cpp/212-Word-Search-II.cpp b/cpp/212-Word-Search-II.cpp new file mode 100644 index 000000000..1c23850c5 --- /dev/null +++ b/cpp/212-Word-Search-II.cpp @@ -0,0 +1,89 @@ +/* + Given a board of characters & a list of words, return all words on the board + + Implement trie, for search: iterate thru children until isWord, add to result + + Time: O(m x (4 x 3^(l - 1))) -> m = # of cells, l = max length of words + Space: O(n) -> n = total number of letters in dictionary (no overlap in Trie) +*/ + +class TrieNode { +public: + TrieNode* children[26]; + bool isWord; + + TrieNode() { + for (int i = 0; i < 26; i++) { + children[i] = NULL; + } + isWord = false; + } +}; + +class Solution { +public: + vector findWords(vector>& board, vector& words) { + for (int i = 0; i < words.size(); i++) { + insert(words[i]); + } + + int m = board.size(); + int n = board[0].size(); + + TrieNode* node = root; + vector result; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + search(board, i, j, m, n, node, "", result); + } + } + + return result; + } +private: + TrieNode* root = new TrieNode(); + + void insert(string word) { + TrieNode* node = root; + int curr = 0; + + for (int i = 0; i < word.size(); i++) { + curr = word[i] - 'a'; + if (node->children[curr] == NULL) { + node->children[curr] = new TrieNode(); + } + node = node->children[curr]; + } + + node->isWord = true; + } + + void search(vector>& board, int i, int j, int m, int n, TrieNode* node, string word, vector& result) { + if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] == '#') { + return; + } + + char c = board[i][j]; + + node = node->children[c - 'a']; + if (node == NULL) { + return; + } + + word += board[i][j]; + if (node->isWord) { + result.push_back(word); + node->isWord = false; + } + + board[i][j] = '#'; + + search(board, i - 1, j, m, n, node, word, result); + search(board, i + 1, j, m, n, node, word, result); + search(board, i, j - 1, m, n, node, word, result); + search(board, i, j + 1, m, n, node, word, result); + + board[i][j] = c; + } +}; diff --git a/cpp/213-House-Robber-II.cpp b/cpp/213-House-Robber-II.cpp new file mode 100644 index 000000000..33998c157 --- /dev/null +++ b/cpp/213-House-Robber-II.cpp @@ -0,0 +1,40 @@ +/* + Given int array in a circle, return max amount can rob (can't rob adj houses) + Ex. nums = [2,3,2] -> 3, can't rob house 1 & 3 b/c circular adj, so rob 2 + + Recursion w/ memo -> DP, rob either 2 away + here, or 1 away, try both ranges + Recurrence relation: robFrom[i] = max(robFrom[i-2] + nums[i], robFrom[i-1]) + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int rob(vector& nums) { + int n = nums.size(); + + if (n == 1) { + return nums[0]; + } + + int range1 = robber(nums, 0, n - 2); + int range2 = robber(nums, 1, n - 1); + + return max(range1, range2); + } +private: + int robber(vector& nums, int start, int end) { + int prev = 0; + int curr = 0; + int next = 0; + + for (int i = start; i <= end; i++) { + next = max(prev + nums[i], curr); + prev = curr; + curr = next; + } + + return curr; + } +}; diff --git a/cpp/215-Kth-Largest-Element-In-Array.cpp b/cpp/215-Kth-Largest-Element-In-Array.cpp new file mode 100644 index 000000000..cce145d8e --- /dev/null +++ b/cpp/215-Kth-Largest-Element-In-Array.cpp @@ -0,0 +1,67 @@ +/* + Given array and int k, return kth largest element in array + Ex. nums = [3,2,1,5,6,4], k = 2 -> 5 + + Quickselect, partition until pivot = k, left side all > k + + Time: O(n) -> optimized from O(n log k) min heap solution + Space: O(1) +*/ + +// class Solution { +// public: +// int findKthLargest(vector& nums, int k) { +// priority_queue, greater> pq; +// for (int i = 0; i < nums.size(); i++) { +// pq.push(nums[i]); +// if (pq.size() > k) { +// pq.pop(); +// } +// } +// return pq.top(); +// } +// }; + +class Solution { +public: + int findKthLargest(vector& nums, int k) { + int low = 0; + int high = nums.size() - 1; + int pivotIndex = nums.size(); + + while (pivotIndex != k - 1) { + pivotIndex = partition(nums, low, high); + if (pivotIndex < k - 1) { + low = pivotIndex + 1; + } else { + high = pivotIndex - 1; + } + } + + return nums[k - 1]; + } +private: + int partition(vector& nums, int low, int high) { + int pivot = nums[low]; + + int i = low + 1; + int j = high; + + while (i <= j) { + if (nums[i] < pivot && pivot < nums[j]) { + swap(nums[i], nums[j]); + i++; + j--; + } + if (nums[i] >= pivot) { + i++; + } + if (pivot >= nums[j]) { + j--; + } + } + + swap(nums[low], nums[j]); + return j; + } +}; diff --git a/cpp/217-Contains-Duplicate.cpp b/cpp/217-Contains-Duplicate.cpp new file mode 100644 index 000000000..d47474175 --- /dev/null +++ b/cpp/217-Contains-Duplicate.cpp @@ -0,0 +1,25 @@ +/* + Given int array, return true if any value appears at least twice + Ex. nums = [1,2,3,1] -> true, nums = [1,2,3,4] -> false + + If seen num previously then has dupe, else insert into hash set + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + bool containsDuplicate(vector& nums) { + unordered_set s; + + for (int i = 0; i < nums.size(); i++) { + if (s.find(nums[i]) != s.end()) { + return true; + } + s.insert(nums[i]); + } + + return false; + } +}; diff --git a/cpp/22-Generate-Parentheses.cpp b/cpp/22-Generate-Parentheses.cpp new file mode 100644 index 000000000..76937481d --- /dev/null +++ b/cpp/22-Generate-Parentheses.cpp @@ -0,0 +1,31 @@ +/* + Given n pairs of parentheses, generate all combos of well-formed parentheses + Ex. n = 3 -> ["((()))","(()())","(())()","()(())","()()()"], n = 1 -> ["()"] + + Backtracking, keep valid, favor trying opens, then try closes if still valid + + Time: O(2^n) + Space: O(n) +*/ + +class Solution { +public: + vector generateParenthesis(int n) { + vector result; + generate(n, 0, 0, "", result); + return result; + } +private: + void generate(int n, int open, int close, string str, vector& result) { + if (open == n && close == n) { + result.push_back(str); + return; + } + if (open < n) { + generate(n, open + 1, close, str + '(', result); + } + if (open > close) { + generate(n, open, close + 1, str + ')', result); + } + } +}; diff --git a/cpp/226-Invert-Binary-Tree.cpp b/cpp/226-Invert-Binary-Tree.cpp new file mode 100644 index 000000000..266b934e8 --- /dev/null +++ b/cpp/226-Invert-Binary-Tree.cpp @@ -0,0 +1,33 @@ +/* + Given the root of a binary tree, invert the tree, and return its root + Ex. root = [4,2,7,1,3,6,9] -> [4,7,2,9,6,3,1], [2,1,3] -> [2,3,1] + + Preorder traversal, at each node, swap it's left and right children + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + TreeNode* invertTree(TreeNode* root) { + if (root == NULL) { + return NULL; + } + swap(root->left, root->right); + invertTree(root->left); + invertTree(root->right); + return root; + } +}; diff --git a/cpp/23-Merge-K-Sorted-Lists.cpp b/cpp/23-Merge-K-Sorted-Lists.cpp new file mode 100644 index 000000000..26fb63d89 --- /dev/null +++ b/cpp/23-Merge-K-Sorted-Lists.cpp @@ -0,0 +1,106 @@ +/* + Given array of k sorted linked-lists, merge all into 1 sorted list + Ex. lists = [[1,4,5],[1,3,4],[2,6]] -> [1,1,2,3,4,4,5,6] + + Min heap -> optimize space w/ divide-and-conquer, merge 2 each time + + Time: O(n log k) + Space: O(n) -> O(1) +*/ + +/** + * 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) {} + * }; + */ + +// class Solution { +// public: +// ListNode* mergeKLists(vector& lists) { +// priority_queue, greater> pq; +// for (int i = 0; i < lists.size(); i++) { +// ListNode* node = lists[i]; +// while (node != NULL) { +// pq.push(node->val); +// node = node->next; +// } +// } +// if (pq.empty()) { +// return NULL; +// } +// ListNode* node = new ListNode(pq.top()); +// pq.pop(); +// ListNode* head = node; +// while (!pq.empty()) { +// node->next = new ListNode(pq.top()); +// pq.pop(); +// node = node->next; +// } +// return head; +// } +// }; + +class Solution { +public: + ListNode* mergeKLists(vector& lists) { + int n = lists.size(); + if (n == 0) { + return NULL; + } + + while (n > 1) { + for (int i = 0; i < n / 2; i++) { + lists[i] = mergeTwoLists(lists[i], lists[n - i - 1]); + } + n = (n + 1) / 2; + } + + return lists.front(); + } +private: + ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { + if (list1 == NULL && list2 == NULL) { + return NULL; + } + if (list1 == NULL) { + return list2; + } + if (list2 == NULL) { + return list1; + } + + ListNode* head = NULL; + if (list1->val <= list2->val) { + head = list1; + list1 = list1->next; + } else { + head = list2; + list2 = list2->next; + } + ListNode* curr = head; + + while (list1 != NULL && list2 != NULL) { + if (list1->val <= list2->val) { + curr->next = list1; + list1 = list1->next; + } else { + curr->next = list2; + list2 = list2->next; + } + curr = curr->next; + } + + if (list1 == NULL) { + curr->next = list2; + } else { + curr->next = list1; + } + + return head; + } +}; diff --git a/cpp/230-Kth-Smallest-Element-In-A-Bst.cpp b/cpp/230-Kth-Smallest-Element-In-A-Bst.cpp new file mode 100644 index 000000000..1a8f97f3d --- /dev/null +++ b/cpp/230-Kth-Smallest-Element-In-A-Bst.cpp @@ -0,0 +1,42 @@ +/* + Given root of BST & int k, return kth smallest value (1-indexed) of all values in tree + Ex. root = [3,1,4,null,2] k = 1 -> 1, root = [5,3,6,2,4,null,null,1] k = 3 -> 3 + + Inorder traversal, each visit decrement k, when k = 0 return, works because inorder + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + int kthSmallest(TreeNode* root, int k) { + int result = 0; + inorder(root, k, result); + return result; + } +private: + void inorder(TreeNode* root, int& k, int& result) { + if (root == NULL) { + return; + } + inorder(root->left, k, result); + k--; + if (k == 0) { + result = root->val; + return; + } + inorder(root->right, k, result); + } +}; diff --git a/cpp/235-Lowest-Common-Ancestor-Of-A-Binary-Search-Tree.cpp b/cpp/235-Lowest-Common-Ancestor-Of-A-Binary-Search-Tree.cpp new file mode 100644 index 000000000..15883fd1e --- /dev/null +++ b/cpp/235-Lowest-Common-Ancestor-Of-A-Binary-Search-Tree.cpp @@ -0,0 +1,47 @@ +/* + Given a binary search tree (BST), find the LCA of 2 given nodes in the BST + + Use BST property: if curr > left & right go left, else if < go right, else done + + Time: O(n) + Space: O(n) +*/ + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ + +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (p->val < root->val && q->val < root->val) { + return lowestCommonAncestor(root->left, p, q); + } else if (p->val > root->val && q->val > root->val) { + return lowestCommonAncestor(root->right, p, q); + } else { + return root; + } + } +}; + +// class Solution { +// public: +// TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { +// while (root != NULL) { +// if (p->val < root->val && q->val < root->val) { +// root = root->left; +// } else if (p->val > root->val && q->val > root->val) { +// root = root->right; +// } else { +// return root; +// } +// } +// return NULL; +// } +// }; diff --git a/cpp/238-Product-Of-Array-Except-Self.cpp b/cpp/238-Product-Of-Array-Except-Self.cpp new file mode 100644 index 000000000..4eac22fd1 --- /dev/null +++ b/cpp/238-Product-Of-Array-Except-Self.cpp @@ -0,0 +1,32 @@ +/* + Given an integer array nums, return an array such that: + answer[i] is equal to the product of all elements of nums except nums[i] + Ex. nums = [1,2,3,4] -> [24,12,8,6], nums = [-1,1,0,-3,3] -> [0,0,9,0,0] + + Calculate prefix products forward, then postfix backwards in a 2nd pass + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + vector productExceptSelf(vector& nums) { + int n = nums.size(); + vector result(n, 1); + + int prefix = 1; + for (int i = 0; i < n; i++) { + result[i] = prefix; + prefix = prefix * nums[i]; + } + + int postfix = 1; + for (int i = n - 1; i >= 0; i--) { + result[i] = result[i] * postfix; + postfix = postfix * nums[i]; + } + + return result; + } +}; diff --git a/cpp/239-Sliding-Window-Maximum.cpp b/cpp/239-Sliding-Window-Maximum.cpp new file mode 100644 index 000000000..2201f51e7 --- /dev/null +++ b/cpp/239-Sliding-Window-Maximum.cpp @@ -0,0 +1,39 @@ +/* + Given int array & sliding window size k, return max sliding window + Ex. nums = [1,3,-1,-3,5,3,6,7] k = 3 -> [3,3,5,5,6,7] + + Sliding window deque, ensure monotonic decr, leftmost largest + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + vector maxSlidingWindow(vector& nums, int k) { + deque dq; + vector result; + + int i = 0; + int j = 0; + + while (j < nums.size()) { + while (!dq.empty() && nums[dq.back()] < nums[j]) { + dq.pop_back(); + } + dq.push_back(j); + + if (i > dq.front()) { + dq.pop_front(); + } + + if (j + 1 >= k) { + result.push_back(nums[dq.front()]); + i++; + } + j++; + } + + return result; + } +}; diff --git a/cpp/242-Valid-Anagram-Hashmap.cpp b/cpp/242-Valid-Anagram-Hashmap.cpp new file mode 100644 index 000000000..8acae385b --- /dev/null +++ b/cpp/242-Valid-Anagram-Hashmap.cpp @@ -0,0 +1,21 @@ +// hashmap solution, similar to neetcode python implementation + +class Solution { +public: + bool isAnagram(string s, string t) { + if(s.size() != t.size()) return false; + + unordered_map smap; + unordered_map tmap; + + for(int i = 0; i < s.size(); i++){ + smap[s[i]]++; + tmap[t[i]]++; + } + + for(int i = 0; i < smap.size(); i++){ + if(smap[i] != tmap[i]) return false; + } + return true; + } +}; \ No newline at end of file diff --git a/cpp/242-Valid-Anagram.cpp b/cpp/242-Valid-Anagram.cpp new file mode 100644 index 000000000..307676a45 --- /dev/null +++ b/cpp/242-Valid-Anagram.cpp @@ -0,0 +1,32 @@ +/* + Given 2 strings, return true if anagrams (same letters diff order) + Ex. s = "anagram" & t = "nagaram" -> true, s = "rat" & t = "car" -> false + + Count chars, strings should have same # of chars if anagram + + Time: O(n) + Space: O(26) +*/ + +class Solution { +public: + bool isAnagram(string s, string t) { + if (s.size() != t.size()) { + return false; + } + + vector count(26); + + for (int i = 0; i < s.size(); i++) { + count[s[i] - 'a']++; + } + + for (int j = 0; j < t.size(); j++) { + count[t[j] - 'a']--; + if (count[t[j] - 'a'] < 0) { + return false; + } + } + return true; + } +}; diff --git a/cpp/25-Reverse-Nodes-In-K-Group.cpp b/cpp/25-Reverse-Nodes-In-K-Group.cpp new file mode 100644 index 000000000..6dce22a54 --- /dev/null +++ b/cpp/25-Reverse-Nodes-In-K-Group.cpp @@ -0,0 +1,58 @@ +/* + Given head of linked list, reverse nodes of list k at a time + Ex. head = [1,2,3,4,5], k = 2 -> [2,1,4,3,5] + + Maintain prev, curr, & temp pointers to reverse, count k times + + Time: O(n) + Space: O(1) +*/ + +/** + * 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) {} + * }; + */ +class Solution { +public: + ListNode* reverseKGroup(ListNode* head, int k) { + ListNode* dummy = new ListNode(); + dummy->next = head; + + ListNode* prev = dummy; + ListNode* curr = dummy->next; + ListNode* temp = NULL; + + int count = k; + + while (curr != NULL) { + if (count > 1) { + temp = prev->next; + prev->next = curr->next; + curr->next = curr->next->next; + prev->next->next = temp; + + count--; + } else { + prev = curr; + curr = curr->next; + count = k; + + ListNode* end = curr; + for (int i = 0; i < k; i++) { + if (end == NULL) { + return dummy->next; + } + end = end->next; + } + } + } + + return dummy->next; + } +}; diff --git a/cpp/252-Meeting-Rooms.cpp b/cpp/252-Meeting-Rooms.cpp new file mode 100644 index 000000000..5689ecda6 --- /dev/null +++ b/cpp/252-Meeting-Rooms.cpp @@ -0,0 +1,26 @@ +/* + Given array of time intervals, determine if can attend all meetings + Ex. intervals = [[0,30],[5,10],[15,20]] -> false + + Sort by start time, check adj meetings, if overlap return false + + Time: O(n log n) + Space: O(1) +*/ + +class Solution { +public: + bool canAttendMeetings(vector>& intervals) { + if (intervals.empty()) { + return true; + } + + sort(intervals.begin(), intervals.end()); + for (int i = 0; i < intervals.size() - 1; i++) { + if (intervals[i][1] > intervals[i + 1][0]) { + return false; + } + } + return true; + } +}; diff --git a/cpp/253-Meeting-Rooms-II.cpp b/cpp/253-Meeting-Rooms-II.cpp new file mode 100644 index 000000000..2c073f94a --- /dev/null +++ b/cpp/253-Meeting-Rooms-II.cpp @@ -0,0 +1,32 @@ +/* + Given array of time intervals, determine min # of meeting rooms required + Ex. intervals = [[0,30],[5,10],[15,20]] -> 2 + + Min heap for earliest end times, most overlap will be heap size + + Time: O(n log n) + Space: O(n) +*/ + +class Solution { +public: + int minMeetingRooms(vector>& intervals) { + // sort intervals by start time + sort(intervals.begin(), intervals.end()); + + // min heap to track min end time of merged intervals + priority_queue, greater> pq; + pq.push(intervals[0][1]); + + for (int i = 1; i < intervals.size(); i++) { + // compare curr start w/ earliest end time, if no overlap then pop + if (intervals[i][0] >= pq.top()) { + pq.pop(); + } + // add new room (will replace/be same size if above was true) + pq.push(intervals[i][1]); + } + + return pq.size(); + } +}; diff --git a/cpp/261-Graph-Valid-Tree.cpp b/cpp/261-Graph-Valid-Tree.cpp new file mode 100644 index 000000000..e5beeb304 --- /dev/null +++ b/cpp/261-Graph-Valid-Tree.cpp @@ -0,0 +1,49 @@ +/* + Graph of nodes, list of edges, determine if edges make valid tree + Ex. n = 5, edges = [[0,1],[0,2],[0,3],[1,4]] -> true + + (1) For graph to be a valid tree, must have exactly n - 1 edges + (2) If graph fully connected & has n - 1 edges, can't contain cycle + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + bool validTree(int n, vector>& edges) { + vector> adj(n); + for (int i = 0; i < edges.size(); i++) { + vector edge = edges[i]; + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + vector visited(n); + if (hasCycle(adj, visited, -1, 0)) { + return false; + } + + for (int i = 0; i < visited.size(); i++) { + if (!visited[i]) { + return false; + } + } + return true; + } +private: + bool hasCycle(vector>& adj, vector& visited, int parent, int child) { + if (visited[child]) { + return true; + } + visited[child] = true; + // checking for cycles and connectedness + for (int i = 0; i < adj[child].size(); i++) { + int curr = adj[child][i]; + if (curr != parent && hasCycle(adj, visited, child, curr)) { + return true; + } + } + return false; + } +}; diff --git a/cpp/268-Missing-Number.cpp b/cpp/268-Missing-Number.cpp new file mode 100644 index 000000000..27233453b --- /dev/null +++ b/cpp/268-Missing-Number.cpp @@ -0,0 +1,25 @@ +/* + Given array in range [0, n], return missing + Ex. nums = [3,0,1] -> 2, nums = [0,1] -> 2 + + Use the fact that XOR is its own inverse + Ex. [0,1,3,4] + Missing = 4^(0^0)^(1^1)^(2^3)^(3^4) + = (4^4)^(0^0)^(1^1)^(3^3)^2 + = 0^0^0^0^2 = 2 + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int missingNumber(vector& nums) { + int n = nums.size(); + int result = n; + for (int i = 0; i < n; i++) { + result ^= i ^ nums[i]; + } + return result; + } +}; diff --git a/cpp/271-Encode-And-Decode-Strings.cpp b/cpp/271-Encode-And-Decode-Strings.cpp new file mode 100644 index 000000000..a6dc11601 --- /dev/null +++ b/cpp/271-Encode-And-Decode-Strings.cpp @@ -0,0 +1,48 @@ +/* + Design algorithm to encode/decode: list of strings <-> string + + Encode/decode w/ non-ASCII delimiter: {len of str, "#", str} + + Time: O(n) + Space: O(1) +*/ + +class Codec { +public: + + // Encodes a list of strings to a single string. + string encode(vector& strs) { + string result = ""; + + for (int i = 0; i < strs.size(); i++) { + string str = strs[i]; + result += to_string(str.size()) + "#" + str; + } + + return result; + } + + // Decodes a single string to a list of strings. + vector decode(string s) { + vector result; + + int i = 0; + while (i < s.size()) { + int j = i; + while (s[j] != '#') { + j++; + } + int length = stoi(s.substr(i, j - i)); + string str = s.substr(j + 1, length); + result.push_back(str); + i = j + 1 + length; + } + + return result; + } +private: +}; + +// Your Codec object will be instantiated and called as such: +// Codec codec; +// codec.decode(codec.encode(strs)); diff --git a/cpp/286-Walls-And-Gates.cpp b/cpp/286-Walls-And-Gates.cpp new file mode 100644 index 000000000..e539eeefb --- /dev/null +++ b/cpp/286-Walls-And-Gates.cpp @@ -0,0 +1,46 @@ +/* + Given grid: -1 wall, 0 gate, INF empty, fill each empty w/ dist to nearest gate + + BFS traversal, shortest path from each gate to all empty rooms + Each gate only looks at within 1 space, then next gate, guarantees shortest + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + void wallsAndGates(vector>& rooms) { + int m = rooms.size(); + int n = rooms[0].size(); + + queue> q; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (rooms[i][j] == 0) { + q.push({i, j}); + } + } + } + + while (!q.empty()) { + int row = q.front().first; + int col = q.front().second; + q.pop(); + + for (int i = 0; i < 4; i++) { + int x = row + dirs[i][0]; + int y = col + dirs[i][1]; + + if (x < 0 || x >= m || y < 0 || y >= n || rooms[x][y] != INT_MAX) { + continue; + } + + rooms[x][y] = rooms[row][col] + 1; + q.push({x, y}); + } + } + } +private: + vector> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; +}; diff --git a/cpp/287-Find-The-Duplicate-Number.cpp b/cpp/287-Find-The-Duplicate-Number.cpp new file mode 100644 index 000000000..a852e1090 --- /dev/null +++ b/cpp/287-Find-The-Duplicate-Number.cpp @@ -0,0 +1,30 @@ +/* + Given int array, return the one repeated number + Ex. nums = [1,3,4,2,2] -> 2, nums = [3,1,3,4,2] -> 3 + + If there's duplicate, must be a cycle, find meeting point + Take 1 back to start, they'll intersect at the duplicate + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int findDuplicate(vector& nums) { + int slow = nums[0]; + int fast = nums[nums[0]]; + + while (slow != fast) { + slow = nums[slow]; + fast = nums[nums[fast]]; + } + + slow = 0; + while (slow != fast) { + slow = nums[slow]; + fast = nums[fast]; + } + return slow; + } +}; diff --git a/cpp/295-Find-Median-From-Data-Stream.cpp b/cpp/295-Find-Median-From-Data-Stream.cpp new file mode 100644 index 000000000..c070cc6aa --- /dev/null +++ b/cpp/295-Find-Median-From-Data-Stream.cpp @@ -0,0 +1,66 @@ +/* + Implement data structure that gets the median from a data stream + + Max heap of lower values & min heap of higher values, access to mids + + Time: O(log n) + O(1) + Space: O(n) +*/ + +class MedianFinder { +public: + MedianFinder() { + + } + + void addNum(int num) { + if (lower.empty()) { + lower.push(num); + return; + } + + if (lower.size() > higher.size()) { + if (lower.top() > num) { + higher.push(lower.top()); + lower.pop(); + lower.push(num); + } else { + higher.push(num); + } + } else { + if (num > higher.top()) { + lower.push(higher.top()); + higher.pop(); + higher.push(num); + } else { + lower.push(num); + } + } + } + + double findMedian() { + double result = 0.0; + + if (lower.size() == higher.size()) { + result = lower.top() + (higher.top() - lower.top()) / 2.0; + } else { + if (lower.size() > higher.size()) { + result = lower.top(); + } else { + result = higher.top(); + } + } + + return result; + } +private: + priority_queue lower; + priority_queue, greater> higher; +}; + +/** + * Your MedianFinder object will be instantiated and called as such: + * MedianFinder* obj = new MedianFinder(); + * obj->addNum(num); + * double param_2 = obj->findMedian(); + */ diff --git a/cpp/297-Serialize-And-Deserialize-Binary-Tree.cpp b/cpp/297-Serialize-And-Deserialize-Binary-Tree.cpp new file mode 100644 index 000000000..d747ea8e8 --- /dev/null +++ b/cpp/297-Serialize-And-Deserialize-Binary-Tree.cpp @@ -0,0 +1,69 @@ +/* + Design an algorithm to serialize & deserialize a binary tree + + Use stringstream to concisely handle negatives, nulls, etc. + + Time: O(n) serialize, O(n) deserialize + Space: O(n) serialize, O(n) deserialize +*/ + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Codec { +public: + + // Encodes a tree to a single string. + string serialize(TreeNode* root) { + ostringstream out; + encode(root, out); + return out.str(); + } + + // Decodes your encoded data to tree. + TreeNode* deserialize(string data) { + istringstream in(data); + return decode(in); + } + +private: + + void encode(TreeNode* root, ostringstream& out) { + if (root == NULL) { + out << "N "; + return; + } + + out << root->val << " "; + + encode(root->left, out); + encode(root->right, out); + } + + TreeNode* decode(istringstream& in) { + string value = ""; + in >> value; + + if (value == "N") { + return NULL; + } + + TreeNode* root = new TreeNode(stoi(value)); + + root->left = decode(in); + root->right = decode(in); + + return root; + } + +}; + +// Your Codec object will be instantiated and called as such: +// Codec ser, deser; +// TreeNode* ans = deser.deserialize(ser.serialize(root)); diff --git a/cpp/3-Longest-Substring-Without-Repeating-Characters.cpp b/cpp/3-Longest-Substring-Without-Repeating-Characters.cpp new file mode 100644 index 000000000..cdf3aaaf1 --- /dev/null +++ b/cpp/3-Longest-Substring-Without-Repeating-Characters.cpp @@ -0,0 +1,34 @@ +/* + Given string, find longest substring w/o repeating chars + Ex. s = "abcabcbb" -> 3 "abc", s = "bbbbb" -> 1 "b" + + Sliding window, expand if unique, contract if duplicate + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + int lengthOfLongestSubstring(string s) { + unordered_set letters; + + int i = 0; + int j = 0; + + int result = 0; + + while (j < s.size()) { + if (letters.find(s[j]) == letters.end()) { + letters.insert(s[j]); + result = max(result, j - i + 1); + j++; + } else { + letters.erase(s[i]); + i++; + } + } + + return result; + } +}; diff --git a/cpp/300-Longest-Increasing-Subsequence.cpp b/cpp/300-Longest-Increasing-Subsequence.cpp new file mode 100644 index 000000000..c1a3ccd1b --- /dev/null +++ b/cpp/300-Longest-Increasing-Subsequence.cpp @@ -0,0 +1,40 @@ +/* + Given int array, return length of longest increasing subsequence + Ex. nums = [10,9,2,5,3,7,101,18] -> 4, [2,3,7,101] + + Why DP? 1) Max/min of smth, 2) make decisions based on prev decisions + "Decision": is it worth it to consider this number? + If use may contribute to better LIS, but may also eliminate an even better LIS + + Framework to solve DP: + 1) Need some function or array that represents ans to the problem (dp array) + 2) Way to transition b/w states (recurrence relation), depends on question + 3) Need a base case (initial solution for every subproblem) + + Recurrence relation: dp[i] = max(dp[j] + 1) + Base case: dp[i] = 1, since every element on its own has an LIS of 1 + + Time: O(n^2) + Space: O(n) +*/ + +class Solution { +public: + int lengthOfLIS(vector& nums) { + int n = nums.size(); + vector dp(n, 1); + + int result = 1; + + for (int i = 1; i < n; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + result = max(result, dp[i]); + } + + return result; + } +}; diff --git a/cpp/309-Best-Time-To-Buy-And-Sell-Stock-With-Cooldown.cpp b/cpp/309-Best-Time-To-Buy-And-Sell-Stock-With-Cooldown.cpp new file mode 100644 index 000000000..eb1f4d513 --- /dev/null +++ b/cpp/309-Best-Time-To-Buy-And-Sell-Stock-With-Cooldown.cpp @@ -0,0 +1,48 @@ +/* + Array of stock prices, find max profit + After a sell cooldown of 1 day, can't engage in multiple transactions + Ex. prices = [1,2,3,0,2] -> 3, transactions = [buy,sell,cd,buy,sell] + + DP + state machine: held ---> sold ---> reset ---> held + sell rest buy + + Time: O(n) + Space: O(1) -> optimized from O(n) since only need i - 1 prev state +*/ + +// class Solution { +// public: +// int maxProfit(vector& prices) { +// int n = prices.size(); +// vector s0(n, 0); +// vector s1(n, 0); +// vector s2(n, 0); +// s0[0] = 0; +// s1[0] = -prices[0]; +// s2[0] = INT_MIN; +// for (int i = 1; i < n; i++) { +// s0[i] = max(s0[i - 1], s2[i - 1]); +// s1[i] = max(s1[i - 1], s0[i - 1] - prices[i]); +// s2[i] = s1[i - 1] + prices[i]; +// } +// return max(s0[n - 1], s2[n - 1]); +// } +// }; + +class Solution { +public: + int maxProfit(vector& prices) { + int sold = 0; + int hold = INT_MIN; + int rest = 0; + + for (int i = 0; i < prices.size(); i++) { + int prevSold = sold; + sold = hold + prices[i]; + hold = max(hold, rest - prices[i]); + rest = max(rest, prevSold); + } + + return max(sold, rest); + } +}; diff --git a/cpp/312-Burst-Balloons.cpp b/cpp/312-Burst-Balloons.cpp new file mode 100644 index 000000000..fece390c4 --- /dev/null +++ b/cpp/312-Burst-Balloons.cpp @@ -0,0 +1,52 @@ +/* + Given array of balloons w/ coins, if burst ith, get (i-1) + i + (i+1) coins + Return max coins can collect by bursting the balloons wisely + + DP to return max coins obtainable in each interval [left, right] + Divide & conquer left & right depends on previous bursts, so think backwards + Instead of which one to burst first, need to think which one to burst last + + Time: O(n^3) -> O(n^2) states, for each states, determining max coins is O(n) + Space: O(n^2) -> O(n^2) to store all states +*/ + +class Solution { +public: + int maxCoins(vector& nums) { + // add 1 before & after nums + nums.insert(nums.begin(), 1); + nums.insert(nums.end(), 1); + int n = nums.size(); + + // cache results of dp + vector> memo(n, vector(n, 0)); + + // 1 & n - 2 since we can't burst our fake balloons + return dp(nums, memo, 1, n - 2); + } +private: + int dp(vector& nums, vector>& memo, int left, int right) { + // base case interval is empty, yields 0 coins + if (right - left < 0) { + return 0; + } + + // we've already seen this, return from cache + if (memo[left][right] > 0) { + return memo[left][right]; + } + + // find the last burst in nums[left]...nums[right] + int result = 0; + for (int i = left; i <= right; i++) { + // nums[i] is the last burst + int curr = nums[left - 1] * nums[i] * nums[right + 1]; + // nums[i] is fixed, recursively call left & right sides + int remaining = dp(nums, memo, left, i - 1) + dp(nums, memo, i + 1, right); + result = max(result, curr + remaining); + } + // add to cache + memo[left][right] = result; + return result; + } +}; diff --git a/cpp/322-Coin-Change.cpp b/cpp/322-Coin-Change.cpp new file mode 100644 index 000000000..7ba78ae6e --- /dev/null +++ b/cpp/322-Coin-Change.cpp @@ -0,0 +1,30 @@ +/* + Given array of coins & an amount, return fewest coins to make that amount + Ex. coins = [1,2,5], amount = 11 -> 3, $11 = $5 + $5 + $1 + + Compute all min counts for amounts up to i, "simulate" use of a coin + + Time: O(m x n) -> m = # of coins, n = amount + Space: O(n) +*/ + +class Solution { +public: + int coinChange(vector& coins, int amount) { + vector dp(amount + 1, amount + 1); + dp[0] = 0; + + for (int i = 1; i < amount + 1; i++) { + for (int j = 0; j < coins.size(); j++) { + if (i - coins[j] >= 0) { + dp[i] = min(dp[i], 1 + dp[i - coins[j]]); + } + } + } + + if (dp[amount] == amount + 1) { + return -1; + } + return dp[amount]; + } +}; diff --git a/cpp/323-Number-Of-Connected-Components-In-An-Undirected-Graph.cpp b/cpp/323-Number-Of-Connected-Components-In-An-Undirected-Graph.cpp new file mode 100644 index 000000000..6253c33d2 --- /dev/null +++ b/cpp/323-Number-Of-Connected-Components-In-An-Undirected-Graph.cpp @@ -0,0 +1,57 @@ +/* + Graph of n nodes, given edges array, return # of connected components + Ex. n = 5, edges = [[0,1],[1,2],[3,4]] -> 2 + + Union find, for each edge combine, if already in same set keep traversing + If not in same set, decrement count by 1, count will store # of components + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + int countComponents(int n, vector>& edges) { + vector parents; + vector ranks; + for (int i = 0; i < n; i++) { + parents.push_back(i); + ranks.push_back(1); + } + + int result = n; + for (int i = 0; i < edges.size(); i++) { + int n1 = edges[i][0]; + int n2 = edges[i][1]; + result -= doUnion(parents, ranks, n1, n2); + } + return result; + } +private: + int doFind(vector& parents, int n) { + int p = parents[n]; + while (p != parents[p]) { + parents[p] = parents[parents[p]]; + p = parents[p]; + } + return p; + } + + int doUnion(vector& parents, vector& ranks, int n1, int n2) { + int p1 = doFind(parents, n1); + int p2 = doFind(parents, n2); + if (p1 == p2) { + return 0; + } + + if (ranks[p1] > ranks[p2]) { + parents[p2] = p1; + ranks[p1] += ranks[p2]; + } else { + parents[p1] = p2; + ranks[p2] += ranks[p1]; + } + + return 1; + } +}; diff --git a/cpp/329-Longest-Increasing-Path-In-A-Matrix.cpp b/cpp/329-Longest-Increasing-Path-In-A-Matrix.cpp new file mode 100644 index 000000000..5beb7f174 --- /dev/null +++ b/cpp/329-Longest-Increasing-Path-In-A-Matrix.cpp @@ -0,0 +1,48 @@ +/* + Given matrix, return length of longest increasing path + Ex. matrix = [[9,9,4],[6,6,8],[2,1,1]] -> 4, [1,2,6,9] + + DFS + memo, cache on indices, compare to prev for increasing check + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int longestIncreasingPath(vector>& matrix) { + int m = matrix.size(); + int n = matrix[0].size(); + + int result = 0; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + result = max(result, dfs(matrix, -1, i, j, m, n)); + } + } + + return result; + } +private: + // {(i, j) -> longest increasing path at (i, j)} + map, int> dp; + + int dfs(vector>& matrix, int prev, int i, int j, int m, int n) { + if (i < 0 || i >= m || j < 0 || j >= n || matrix[i][j] <= prev) { + return 0; + } + if (dp.find({i, j}) != dp.end()) { + return dp[{i, j}]; + } + + int result = 1; + result = max(result, 1 + dfs(matrix, matrix[i][j], i - 1, j, m, n)); + result = max(result, 1 + dfs(matrix, matrix[i][j], i + 1, j, m, n)); + result = max(result, 1 + dfs(matrix, matrix[i][j], i, j - 1, m, n)); + result = max(result, 1 + dfs(matrix, matrix[i][j], i, j + 1, m, n)); + dp[{i, j}] = result; + + return dp[{i, j}]; + } +}; diff --git a/cpp/33-Search-In-Rotated-Sorted-Array.cpp b/cpp/33-Search-In-Rotated-Sorted-Array.cpp new file mode 100644 index 000000000..2e84ff3a9 --- /dev/null +++ b/cpp/33-Search-In-Rotated-Sorted-Array.cpp @@ -0,0 +1,39 @@ +/* + Given array after some possible rotation, find if target is in nums + Ex. nums = [4,5,6,7,0,1,2] target = 0 -> 4 (value 0 is at index 4) + + Modified binary search, if low <= mid left sorted, else right sorted + + Time: O(log n) + Space: O(1) +*/ + +class Solution { +public: + int search(vector& nums, int target) { + int low = 0; + int high = nums.size() - 1; + + while (low <= high) { + int mid = low + (high - low) / 2; + if (nums[mid] == target) { + return mid; + } + if (nums[low] <= nums[mid]) { + if (nums[low] <= target && target <= nums[mid]) { + high = mid - 1; + } else { + low = mid + 1; + } + } else { + if (nums[mid] <= target && target <= nums[high]) { + low = mid + 1; + } else { + high = mid - 1; + } + } + } + + return -1; + } +}; diff --git a/cpp/332-Reconstruct-Itinerary.cpp b/cpp/332-Reconstruct-Itinerary.cpp new file mode 100644 index 000000000..2b74b8f69 --- /dev/null +++ b/cpp/332-Reconstruct-Itinerary.cpp @@ -0,0 +1,37 @@ +/* + Given airline tickets, find valid itinerary (use all tickets once) + Ex. tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]] + output = ["JFK","MUC","LHR","SFO","SJC"] + + Greedy DFS, build route backwards when retreating, merge cycles into main path + + Time: O(E log (E / V)) -> E = # of flights, V = # of airports, sorting + Space: O(V + E) -> store # of airports & # of flights in hash map +*/ + +class Solution { +public: + vector findItinerary(vector>& tickets) { + unordered_map> m; + for (int i = 0; i < tickets.size(); i++) { + m[tickets[i][0]].insert(tickets[i][1]); + } + + vector result; + dfs(m, "JFK", result); + reverse(result.begin(), result.end()); + return result; + } +private: + void dfs(unordered_map>& m, + string airport, vector& result) { + + while (!m[airport].empty()) { + string next = *m[airport].begin(); + m[airport].erase(m[airport].begin()); + dfs(m, next, result); + } + + result.push_back(airport); + } +}; diff --git a/cpp/338-Counting-Bits.cpp b/cpp/338-Counting-Bits.cpp new file mode 100644 index 000000000..d4fe8465c --- /dev/null +++ b/cpp/338-Counting-Bits.cpp @@ -0,0 +1,25 @@ +/* + Given int, return array: for each i, ans[i] is # of 1's + Ex. n = 2 -> [0,1,1], 0 = 0 has 0, 1 = 1 has 1, 2 = 10 has 1 + + x = 1001011101 = 605 + x'= 0100101110 = 302 + Differ by 1 bit, by removing LSB: f(x) = f(x / 2) + (x mod 2) + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + vector countBits(int n) { + vector result(n + 1, 0); + + for (int i = 1; i <= n; i++) { + // i / 2 i % 2 + result[i] = result[i >> 1] + (i & 1); + } + + return result; + } +}; diff --git a/cpp/347-Top-K-Frequent-Elements.cpp b/cpp/347-Top-K-Frequent-Elements.cpp new file mode 100644 index 000000000..646a9ba38 --- /dev/null +++ b/cpp/347-Top-K-Frequent-Elements.cpp @@ -0,0 +1,65 @@ +/* + Given an integer array nums & an integer k, return the k most frequent elements + Ex. nums = [1,1,1,2,2,3] k = 2 -> [1,2], nums = [1] k = 1 -> [1] + + Heap -> optimize w/ freq map & bucket sort (no freq can be > n), get results from end +*/ + +// Time: O(n log k) +// Space: O(n + k) + +// class Solution { +// public: +// vector topKFrequent(vector& nums, int k) { +// unordered_map m; +// for (int i = 0; i < nums.size(); i++) { +// m[nums[i]]++; +// } +// priority_queue, vector>, greater>> pq; +// for (auto it = m.begin(); it != m.end(); it++) { +// pq.push({it->second, it->first}); +// if (pq.size() > k) { +// pq.pop(); +// } +// } +// vector result; +// while (!pq.empty()) { +// result.push_back(pq.top().second); +// pq.pop(); +// } +// return result; +// } +// }; + +// Time: O(n) +// Space: O(n) + +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + int n = nums.size(); + + unordered_map m; + for (int i = 0; i < n; i++) { + m[nums[i]]++; + } + + vector> buckets(n + 1); + for (auto it = m.begin(); it != m.end(); it++) { + buckets[it->second].push_back(it->first); + } + + vector result; + + for (int i = n; i >= 0; i--) { + if (result.size() >= k) { + break; + } + if (!buckets[i].empty()) { + result.insert(result.end(), buckets[i].begin(), buckets[i].end()); + } + } + + return result; + } +}; diff --git a/cpp/355-Design-Twitter.cpp b/cpp/355-Design-Twitter.cpp new file mode 100644 index 000000000..f5b88455b --- /dev/null +++ b/cpp/355-Design-Twitter.cpp @@ -0,0 +1,65 @@ +/* + Design Twitter: post tweets, follow/unfollow, see recent tweets + + Maintain user -> tweet pairs & hash map {user -> ppl they follow} + + Time: O(n) + Space: O(n) +*/ + +class Twitter { +public: + Twitter() { + + } + + void postTweet(int userId, int tweetId) { + posts.push_back({userId, tweetId}); + } + + vector getNewsFeed(int userId) { + // 10 tweets + int count = 10; + vector result; + + // since postTweet pushes to the back, looping from back gets most recent + for (int i = posts.size() - 1; i >= 0; i--) { + if (count == 0) { + break; + } + + int followingId = posts[i].first; + int tweetId = posts[i].second; + unordered_set following = followMap[userId]; + // add to result if they're following them or it's a tweet from themself + if (following.find(followingId) != following.end() || followingId == userId) { + result.push_back(tweetId); + count--; + } + } + + return result; + } + + void follow(int followerId, int followeeId) { + followMap[followerId].insert(followeeId); + } + + void unfollow(int followerId, int followeeId) { + followMap[followerId].erase(followeeId); + } +private: + // pairs: [user, tweet] + vector> posts; + // hash map: {user -> people they follow} + unordered_map> followMap; +}; + +/** + * Your Twitter object will be instantiated and called as such: + * Twitter* obj = new Twitter(); + * obj->postTweet(userId,tweetId); + * vector param_2 = obj->getNewsFeed(userId); + * obj->follow(followerId,followeeId); + * obj->unfollow(followerId,followeeId); + */ diff --git a/cpp/36-Valid-Sudoku.cpp b/cpp/36-Valid-Sudoku.cpp new file mode 100644 index 000000000..ec1c25da0 --- /dev/null +++ b/cpp/36-Valid-Sudoku.cpp @@ -0,0 +1,38 @@ +/* + Determine if a 9x9 Sudoku board is valid (no repeats) + + Boolean matrices to store seen values. Check rows, cols, 3x3 sub-boxes + + Time: O(cnt^2) + Space: O(cnt^2) +*/ + +class Solution { +public: + bool isValidSudoku(vector>& board) { + const int cnt = 9; + bool row[cnt][cnt] = {false}; + bool col[cnt][cnt] = {false}; + bool sub[cnt][cnt] = {false}; + + for(int r = 0; r < cnt; ++r){ + for(int c = 0; c < cnt; ++c){ + if(board[r][c] == '.') + continue; // if not number pass + + int idx = board[r][c] - '0' - 1; //char to num idx + int area = (r/3) * 3 + (c/3); + + //if number already exists + if(row[r][idx] || col[c][idx] || sub[area][idx]){ + return false; + } + + row[r][idx] = true; + col[c][idx] = true; + sub[area][idx] = true; + } + } + return true; + } +}; diff --git a/cpp/371-Sum-Of-Two-Integers.cpp b/cpp/371-Sum-Of-Two-Integers.cpp new file mode 100644 index 000000000..0ed0cb1c5 --- /dev/null +++ b/cpp/371-Sum-Of-Two-Integers.cpp @@ -0,0 +1,21 @@ +/* + Given 2 ints, return sum w/o using +/- + Ex. a = 1 b = 2 -> 3, a = 2 b = 3 -> 5 + + XOR for addition, AND for carry bit + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int getSum(int a, int b) { + while (b != 0) { + int carry = a & b; + a = a ^ b; + b = (unsigned)carry << 1; + } + return a; + } +}; diff --git a/cpp/39-Combination-Sum.cpp b/cpp/39-Combination-Sum.cpp new file mode 100644 index 000000000..3172eca8e --- /dev/null +++ b/cpp/39-Combination-Sum.cpp @@ -0,0 +1,37 @@ +/* + Given distinct int array & a target, return list of all unique combos that sum to target + Ex. candidates = [2,3,6,7] target = 7 -> [[2,2,3],[7]] + + Backtracking, generate all combo sums, push/pop + index checking to explore new combos + + Time: O(n^target) + Space: O(target) +*/ + +class Solution { +public: + vector> combinationSum(vector& candidates, int target) { + sort(candidates.begin(), candidates.end()); + + vector curr; + vector> result; + + dfs(candidates, target, 0, 0, curr, result); + return result; + } +private: + void dfs(vector& candidates, int target, int sum, int start, vector& curr, vector>& result) { + if (sum > target) { + return; + } + if (sum == target) { + result.push_back(curr); + return; + } + for (int i = start; i < candidates.size(); i++) { + curr.push_back(candidates[i]); + dfs(candidates, target, sum + candidates[i], i, curr, result); + curr.pop_back(); + } + } +}; diff --git a/cpp/4-Median-Of-Two-Sorted-Arrays.cpp b/cpp/4-Median-Of-Two-Sorted-Arrays.cpp new file mode 100644 index 000000000..d6f3f5d58 --- /dev/null +++ b/cpp/4-Median-Of-Two-Sorted-Arrays.cpp @@ -0,0 +1,62 @@ +/* + Given 2 sorted arrays of size m & n, return the median of these arrays + Ex. nums1 = [1,3] nums2 = [2] -> 2, nums1 = [1,2] nums2 = [3,4] -> 2.5 + + Binary search, partition each array until partitions are correct, get median + [1,2,3,4,5] + | a|b | + [1,2,3,4,5,6,7,8] --> a <= d ? yes, c <= b ? no, so need to fix + | c|d | + + Time: O(log min(m, n)) + Space: O(1) +*/ + +class Solution { +public: + double findMedianSortedArrays(vector& nums1, vector& nums2) { + int m = nums1.size(); + int n = nums2.size(); + + if (m > n) { + return findMedianSortedArrays(nums2, nums1); + } + + int total = m + n; + + int low = 0; + int high = m; + + double result = 0.0; + + while (low <= high) { + // nums1 + int i = low + (high - low) / 2; + // nums2 + int j = (total + 1) / 2 - i; + + int left1 = (i > 0) ? nums1[i - 1] : INT_MIN; + int right1 = (i < m) ? nums1[i] : INT_MAX; + int left2 = (j > 0) ? nums2[j - 1] : INT_MIN; + int right2 = (j < n) ? nums2[j] : INT_MAX; + + // partition is correct + if (left1 <= right2 && left2 <= right1) { + // even + if (total % 2 == 0) { + result = (max(left1, left2) + min(right1, right2)) / 2.0; + // odd + } else { + result = max(left1, left2); + } + break; + } else if (left1 > right2) { + high = i - 1; + } else { + low = i + 1; + } + } + + return result; + } +}; diff --git a/cpp/40-Combination-Sum-II.cpp b/cpp/40-Combination-Sum-II.cpp new file mode 100644 index 000000000..67ddf460b --- /dev/null +++ b/cpp/40-Combination-Sum-II.cpp @@ -0,0 +1,40 @@ +/* + Given array & a target, find all unique combos that sum to target, nums can only be used once + Ex. candidates = [10,1,2,7,6,1,5], target = 8 -> [[1,1,6],[1,2,5],[1,7],[2,6]] + + Backtracking, generate all combo sums, push/pop + index checking to explore new combos + + Time: O(2^n) + Space: O(n) +*/ + +class Solution { +public: + vector> combinationSum2(vector& candidates, int target) { + sort(candidates.begin(), candidates.end()); + + vector curr; + vector> result; + + dfs(candidates, target, 0, 0, curr, result); + return result; + } +private: + void dfs(vector& candidates, int target, int sum, int start, vector& curr, vector>& result) { + if (sum > target) { + return; + } + if (sum == target) { + result.push_back(curr); + return; + } + for (int i = start; i < candidates.size(); i++) { + if (i > start && candidates[i] == candidates[i - 1]) { + continue; + } + curr.push_back(candidates[i]); + dfs(candidates, target, sum + candidates[i], i + 1, curr, result); + curr.pop_back(); + } + } +}; diff --git a/cpp/416-Partition-Equal-Subset-Sum.cpp b/cpp/416-Partition-Equal-Subset-Sum.cpp new file mode 100644 index 000000000..e91cdccb0 --- /dev/null +++ b/cpp/416-Partition-Equal-Subset-Sum.cpp @@ -0,0 +1,42 @@ +/* + Given non-empty, non-negative integer array nums, find if: + Can be partitionined into 2 subsets such that sums are equal + Ex. nums = [1,5,11,5] -> true, [1,5,5] & [11], both add to 11 + + Maintain DP set, for each num, check if num in set + curr = target + If not, add curr to every num in set we checked & iterate + + Time: O(n x sum(nums)) + Space: O(sum(nums)) +*/ + +class Solution { +public: + bool canPartition(vector& nums) { + int target = 0; + for (int i = 0; i < nums.size(); i++) { + target += nums[i]; + } + if (target % 2 != 0) { + return false; + } + target /= 2; + + unordered_set dp; + dp.insert(0); + + for (int i = 0; i < nums.size(); i++) { + unordered_set dpNext; + for (auto it = dp.begin(); it != dp.end(); it++) { + if (*it + nums[i] == target) { + return true; + } + dpNext.insert(*it + nums[i]); + dpNext.insert(*it); + } + dp = dpNext; + } + + return false; + } +}; diff --git a/cpp/417-Pacific-Atlantic-Water-Flow.cpp b/cpp/417-Pacific-Atlantic-Water-Flow.cpp new file mode 100644 index 000000000..8acd119db --- /dev/null +++ b/cpp/417-Pacific-Atlantic-Water-Flow.cpp @@ -0,0 +1,61 @@ +/* + Top & left pacific, bottom & right atlantic, determine spots that flow to both + + Instead go outside in, from oceans to spots where rain could flow from + Faster bc avoids repeated work: cells along a path can also reach that ocean + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + vector> pacificAtlantic(vector>& heights) { + int m = heights.size(); + int n = heights[0].size(); + + vector> pacific(m, vector(n)); + vector> atlantic(m, vector(n)); + + for (int i = 0; i < m; i++) { + dfs(heights, pacific, i, 0, m, n); + dfs(heights, atlantic, i, n - 1, m, n); + } + + for (int j = 0; j < n; j++) { + dfs(heights, pacific, 0, j, m, n); + dfs(heights, atlantic, m - 1, j, m, n); + } + + vector> result; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (pacific[i][j] && atlantic[i][j]) { + result.push_back({i, j}); + } + } + } + + return result; + } +private: + void dfs(vector>& heights, vector>& visited, + int i, int j, int m, int n) { + + visited[i][j] = true; + + if (i > 0 && !visited[i - 1][j] && heights[i - 1][j] >= heights[i][j]) { + dfs(heights, visited, i - 1, j, m, n); + } + if (i < m - 1 && !visited[i + 1][j] && heights[i + 1][j] >= heights[i][j]) { + dfs(heights, visited, i + 1, j, m, n); + } + if (j > 0 && !visited[i][j - 1] && heights[i][j - 1] >= heights[i][j]) { + dfs(heights, visited, i, j - 1, m, n); + } + if (j < n - 1 && !visited[i][j + 1] && heights[i][j + 1] >= heights[i][j]) { + dfs(heights, visited, i, j + 1, m, n); + } + } +}; diff --git a/cpp/42-Trapping-Rain-Water.cpp b/cpp/42-Trapping-Rain-Water.cpp new file mode 100644 index 000000000..d9065a6e0 --- /dev/null +++ b/cpp/42-Trapping-Rain-Water.cpp @@ -0,0 +1,38 @@ +/* + Given elevation map array, compute trapped water + Ex. height = [0,1,0,2,1,0,1,3,2,1,2,1] -> 6 + + 2 pointers, outside in, track max left/right + For lower max, curr only dependent on that one + Compute height of these, iterate lower one + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int trap(vector& height) { + int i = 0; + int j = height.size() - 1; + + int maxLeft = height[i]; + int maxRight = height[j]; + + int result = 0; + + while (i < j) { + if (maxLeft <= maxRight) { + i++; + maxLeft = max(maxLeft, height[i]); + result += maxLeft - height[i]; + } else { + j--; + maxRight = max(maxRight, height[j]); + result += maxRight - height[j]; + } + } + + return result; + } +}; diff --git a/cpp/424-Longest-Repeating-Character-Replacement.cpp b/cpp/424-Longest-Repeating-Character-Replacement.cpp new file mode 100644 index 000000000..4b83280ce --- /dev/null +++ b/cpp/424-Longest-Repeating-Character-Replacement.cpp @@ -0,0 +1,36 @@ +/* + Given a string s & an int k, can change any char k times: + Return length of longest substring containing same letter + Ex. s = "ABAB" k = 2 -> 4 "AAAA", s = "AABABBA" k = 1 -> 4 + + Sliding window, expand if can change char, contract if > k + + Time: O(n) + Space: O(26) +*/ + +class Solution { +public: + int characterReplacement(string s, int k) { + vector count(26); + int maxCount = 0; + + int i = 0; + int j = 0; + + int result = 0; + + while (j < s.size()) { + count[s[j] - 'A']++; + maxCount = max(maxCount, count[s[j] - 'A']); + if (j - i + 1 - maxCount > k) { + count[s[i] - 'A']--; + i++; + } + result = max(result, j - i + 1); + j++; + } + + return result; + } +}; diff --git a/cpp/43-Multiply-Strings.cpp b/cpp/43-Multiply-Strings.cpp new file mode 100644 index 000000000..9f228b94f --- /dev/null +++ b/cpp/43-Multiply-Strings.cpp @@ -0,0 +1,34 @@ +/* + Given 2 ints represented as strings, return product, also represented as a string + Ex. num1 = "2" num2 = "3" -> "6", num1 = "123" num2 = "456" -> "56088" + + Standard multiplication, right to left per digit, compute sums & carries at each pos + + Time: O(m x n) + Space: O(m + n) +*/ + +class Solution { +public: + string multiply(string num1, string num2) { + int m = num1.size(); + int n = num2.size(); + + string result(m + n, '0'); + + for (int i = m - 1; i >= 0; i--) { + for (int j = n - 1; j >= 0; j--) { + int sum = (num1[i] - '0') * (num2[j] - '0') + (result[i + j + 1] - '0'); + result[i + j + 1] = sum % 10 + '0'; + result[i + j] += sum / 10; + } + } + + for (int i = 0; i < m + n; i++) { + if (result[i] != '0') { + return result.substr(i); + } + } + return "0"; + } +}; diff --git a/cpp/435-Non-Overlapping-Intervals.cpp b/cpp/435-Non-Overlapping-Intervals.cpp new file mode 100644 index 000000000..08a09eeea --- /dev/null +++ b/cpp/435-Non-Overlapping-Intervals.cpp @@ -0,0 +1,38 @@ +/* + Given array of intervals, return min # of intervals to remove for all non-overlapping + Ex. intervals = [[1,2],[1,3],[2,3],[3,4]] -> 1, remove [1,3] for all non-overlapping + + Remove interval w/ longer end point, since will always overlap more or = vs shorter one + + Time: O(n log n) + Space: O(1) +*/ + +class Solution { +public: + int eraseOverlapIntervals(vector>& intervals) { + int n = intervals.size(); + if (n == 1) { + return 0; + } + + sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { + return a[0] < b[0]; + }); + + int result = 0; + + int i = 0; + while (i < n - 1) { + if (intervals[i][1] > intervals[i+1][0]) { + if (intervals[i][1] < intervals[i+1][1]) { + intervals[i+1] = intervals[i]; + } + result++; + } + i++; + } + + return result; + } +}; diff --git a/cpp/45-Jump-Game-II.cpp b/cpp/45-Jump-Game-II.cpp new file mode 100644 index 000000000..c8486d1d4 --- /dev/null +++ b/cpp/45-Jump-Game-II.cpp @@ -0,0 +1,37 @@ +/* + Given int array, determine min jumps to reach last index + Ex. nums = [2,3,1,1,4] -> 2, index 0 to 1 to last + + Greedy: At each point, determine furthest reachable, jump to it + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int jump(vector& nums) { + int n = nums.size(); + int result = 0; + + int i = 0; + while (i < n - 1) { + if (i + nums[i] >= n - 1) { + result++; + break; + } + int maxIndex = i + 1; + int maxValue = 0; + for (int j = i + 1; j < i + 1 + nums[i]; j++) { + if (j + nums[j] > maxValue) { + maxIndex = j; + maxValue = j + nums[j]; + } + } + i = maxIndex; + result++; + } + + return result; + } +}; diff --git a/cpp/46-Permutations.cpp b/cpp/46-Permutations.cpp new file mode 100644 index 000000000..6b91369a2 --- /dev/null +++ b/cpp/46-Permutations.cpp @@ -0,0 +1,30 @@ +/* + Given array of distinct integers, return all the possible permutations + Ex. nums = [1,2,3] -> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] + + Permute by swapping i/start, DFS from this point, backtrack to undo swap + + Time: O(n x n!) + Space: O(n!) +*/ + +class Solution { +public: + vector> permute(vector& nums) { + vector> result; + dfs(nums, 0, result); + return result; + } +private: + void dfs(vector& nums, int start, vector>& result) { + if (start == nums.size()) { + result.push_back(nums); + return; + } + for (int i = start; i < nums.size(); i++) { + swap(nums[i], nums[start]); + dfs(nums, start + 1, result); + swap(nums[i], nums[start]); + } + } +}; diff --git a/cpp/48-Rotate-Image.cpp b/cpp/48-Rotate-Image.cpp new file mode 100644 index 000000000..6193ff469 --- /dev/null +++ b/cpp/48-Rotate-Image.cpp @@ -0,0 +1,21 @@ +/* + Given a 2D image matrix, rotate image 90 deg CW + + Transpose + reflect (rev on diag then rev left to right) + + Time: O(n^2) + Space: O(1) +*/ + +class Solution { +public: + void rotate(vector>& matrix) { + int n = matrix.size(); + for (int i = 0; i < n; i++) { + for (int j = i; j < n; j++) { + swap(matrix[i][j], matrix[j][i]); + } + reverse(matrix[i].begin(), matrix[i].end()); + } + } +}; diff --git a/cpp/49-Group-Anagrams.cpp b/cpp/49-Group-Anagrams.cpp new file mode 100644 index 000000000..fe5768942 --- /dev/null +++ b/cpp/49-Group-Anagrams.cpp @@ -0,0 +1,39 @@ +/* + Given array of strings, group anagrams together (same letters diff order) + Ex. strs = ["eat","tea","tan","ate","nat","bat"] -> [["bat"],["nat","tan"],["ate","eat","tea"]] + + Count chars, for each string use total char counts (naturally sorted) as key + + Time: O(n x l) -> n = length of strs, l = max length of a string in strs + Space: O(n x l) +*/ + +class Solution { +public: + vector> groupAnagrams(vector& strs) { + unordered_map> m; + for (int i = 0; i < strs.size(); i++) { + string key = getKey(strs[i]); + m[key].push_back(strs[i]); + } + + vector> result; + for (auto it = m.begin(); it != m.end(); it++) { + result.push_back(it->second); + } + return result; + } +private: + string getKey(string str) { + vector count(26); + for (int j = 0; j < str.size(); j++) { + count[str[j] - 'a']++; + } + + string key = ""; + for (int i = 0; i < 26; i++) { + key.append(to_string(count[i] + 'a')); + } + return key; + } +}; diff --git a/cpp/494-Target-Sum.cpp b/cpp/494-Target-Sum.cpp new file mode 100644 index 000000000..83b05eb40 --- /dev/null +++ b/cpp/494-Target-Sum.cpp @@ -0,0 +1,34 @@ +/* + Given int array & a target, want to build expressions w/ '+' & '-' + Return number of different expressions that evaluates to target + + Recursion w/ memoization, cache on (index, total), which stores # ways + If total ever reaches the target, return 1 (this is a way), else 0 + + Time: O(n x target) + Space: O(n x target) +*/ + +class Solution { +public: + int findTargetSumWays(vector& nums, int target) { + return backtrack(nums, target, 0, 0); + } +private: + // {(index, total) -> # of ways} + map, int> dp; + + int backtrack(vector& nums, int target, int i, int total) { + if (i == nums.size()) { + return total == target ? 1 : 0; + } + if (dp.find({i, total}) != dp.end()) { + return dp[{i, total}]; + } + + dp[{i, total}] = backtrack(nums, target, i + 1, total + nums[i]) + + backtrack(nums, target, i + 1, total - nums[i]); + + return dp[{i, total}]; + } +}; diff --git a/cpp/5-Longest-Palindrome-Substring.cpp b/cpp/5-Longest-Palindrome-Substring.cpp new file mode 100644 index 000000000..38c54c462 --- /dev/null +++ b/cpp/5-Longest-Palindrome-Substring.cpp @@ -0,0 +1,35 @@ +/* + Given a string s, return the longest palindromic substring in s + Ex. s = "babad" -> "bab", s = "cbbd" -> "bb" + + Expand around center, extend as far as possible, store max length + + Time: O(n^2) + Space: O(1) +*/ + +class Solution { +public: + string longestPalindrome(string s) { + int maxStart = 0; + int maxLength = 1; + + for (int i = 0; i < s.size() - 1; i++) { + middleOut(s, i, i, maxStart, maxLength); + middleOut(s, i, i + 1, maxStart, maxLength); + } + + return s.substr(maxStart, maxLength); + } +private: + void middleOut(string s, int i, int j, int& maxStart, int& maxLength) { + while (i >= 0 && j <= s.size() - 1 && s[i] == s[j]) { + i--; + j++; + } + if (j - i - 1 > maxLength) { + maxStart = i + 1; + maxLength = j - i - 1; + } + } +}; diff --git a/cpp/50-Pow-X-N.cpp b/cpp/50-Pow-X-N.cpp new file mode 100644 index 000000000..e99dee414 --- /dev/null +++ b/cpp/50-Pow-X-N.cpp @@ -0,0 +1,56 @@ +/* + Implement pow(x, n), which calculates x raised to the power n + Ex. x = 2 n = 10 -> 1024, x = 2.1 n = 3 -> 9.261, x = 2 n = -2 -> 0.25 + + Divide-and-conquer, even x^n = A * A, odd x^n = A * A * x + + Time: O(log n) + Space: O(1) -> optimized from recursive O(log n) to do iteratively +*/ + +// class Solution { +// public: +// double myPow(double x, int n) { +// long exponent = abs(n); +// double result = helper(x, exponent); +// if (n >= 0) { +// return result; +// } +// return 1.0 / result; +// } +// private: +// double helper(double x, long n) { +// if (x == 0.0) { +// return 0; +// } +// if (n == 0) { +// return 1.0; +// } +// double result = helper(x * x, n / 2); +// if (n % 2 == 0) { +// return result; +// } +// return result * x; +// } +// }; + +class Solution { +public: + double myPow(double x, int n) { + long exponent = abs(n); + double curr = x; + double result = 1.0; + + for (long i = exponent; i > 0; i /= 2) { + if (i % 2 == 1) { + result *= curr; + } + curr *= curr; + } + + if (n < 0) { + return 1.0 / result; + } + return result; + } +}; diff --git a/cpp/51-N-Queens.cpp b/cpp/51-N-Queens.cpp new file mode 100644 index 000000000..c7ec56368 --- /dev/null +++ b/cpp/51-N-Queens.cpp @@ -0,0 +1,50 @@ +/* + N-Queens: place n queens such that no 2 queens atk each other, return all soln's + + Place queens per row, try all possibilities & validate for further rows, backtrack + + Time: O(n!) + Space: O(n^2) +*/ + +class Solution { +private: + unordered_set cols; //for Columns + unordered_set negDiag; //for negative diagnals R-C + unordered_set posDiag; //for positive diagnals R+C + + void backtrack(int n, int row, vector>& res, vector& board){ + if(row==n){ + res.push_back(board); + return ; + } + + for(int col = 0; col < n; col++){ //Shifting through each col + if( cols.find(col) != cols.end() or //if queen alread placed in this col + negDiag.find(row - col) != negDiag.end() or //if queen in negDiag + posDiag.find(row + col) != posDiag.end() //if queen in posDiag + ) + continue; + + cols.insert(col); + negDiag.insert(row - col); + posDiag.insert(row + col); + board[row][col] = 'Q'; + + backtrack(n, row +1, res, board); + + cols.erase(col); + negDiag.erase(row - col); + posDiag.erase(row + col); + board[row][col] = '.'; + } + } + +public: + vector> solveNQueens(int n) { + vector> res; + vector board(n, string(n,'.')); + backtrack(n, 0, res, board); + return res; + } +}; diff --git a/cpp/518-Coin-Change-2.cpp b/cpp/518-Coin-Change-2.cpp new file mode 100644 index 000000000..5e5bd0dba --- /dev/null +++ b/cpp/518-Coin-Change-2.cpp @@ -0,0 +1,39 @@ +/* + Given array of coins & an amount, return # of combos that make up this amount + Ex. amount = 5, coins = [1,2,5] -> 4 (5, 2+2+1, 2+1+1+1, 1+1+1+1+1) + + DFS + memo, 2 choices: either try coin & stay at idx, or don't try & proceed + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int change(int amount, vector& coins) { + return dfs(amount, coins, 0, 0); + } +private: + // {(index, sum) -> # of combos that make up this amount} + map, int> dp; + + int dfs(int amount, vector& coins, int i, int sum) { + if (sum == amount) { + return 1; + } + if (sum > amount) { + return 0; + } + if (i == coins.size()) { + return 0; + } + if (dp.find({i, sum}) != dp.end()) { + return dp[{i, sum}]; + } + + dp[{i, sum}] = dfs(amount, coins, i, sum + coins[i]) + + dfs(amount, coins, i + 1, sum); + + return dp[{i, sum}]; + } +}; diff --git a/cpp/53-Maximum-Subarray.cpp b/cpp/53-Maximum-Subarray.cpp new file mode 100644 index 000000000..e358c3b29 --- /dev/null +++ b/cpp/53-Maximum-Subarray.cpp @@ -0,0 +1,24 @@ +/* + Given int array, find contiguous subarray w/ max sum + Ex. nums = [-2,1,-3,4,-1,2,1,-5,4] -> 6, [4,-1,2,1] + + At each point, determine if it's better to add to curr sum or start over + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int maxSubArray(vector& nums) { + int curr = nums[0]; + int result = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + curr = max(curr + nums[i], nums[i]); + result = max(result, curr); + } + + return result; + } +}; diff --git a/cpp/54-Spiral-Matrix.cpp b/cpp/54-Spiral-Matrix.cpp new file mode 100644 index 000000000..f49a7eeff --- /dev/null +++ b/cpp/54-Spiral-Matrix.cpp @@ -0,0 +1,48 @@ +/* + Given a matrix, return all elements in spiral order + + Set up boundaries, go outside in CW: top->right->bottom->left + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + vector spiralOrder(vector>& matrix) { + int left = 0; + int top = 0; + int right = matrix[0].size() - 1; + int bottom = matrix.size() - 1; + + vector result; + + while (top <= bottom && left <= right) { + for (int j = left; j <= right; j++) { + result.push_back(matrix[top][j]); + } + top++; + + for (int i = top; i <= bottom; i++) { + result.push_back(matrix[i][right]); + } + right--; + + if (top <= bottom) { + for (int j = right; j >= left; j--) { + result.push_back(matrix[bottom][j]); + } + } + bottom--; + + if (left <= right) { + for (int i = bottom; i >= top; i--) { + result.push_back(matrix[i][left]); + } + } + left++; + } + + return result; + } +}; diff --git a/cpp/543-Diameter-Of-Binary-Tree.cpp b/cpp/543-Diameter-Of-Binary-Tree.cpp new file mode 100644 index 000000000..3addfe793 --- /dev/null +++ b/cpp/543-Diameter-Of-Binary-Tree.cpp @@ -0,0 +1,40 @@ +/* + Given root of binary tree, return length of diameter of tree (longest path b/w any 2 nodes) + + Max path b/w 2 leaf nodes, "1 +" to add path + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + int diameterOfBinaryTree(TreeNode* root) { + int result = 0; + dfs(root, result); + return result; + } +private: + int dfs(TreeNode* root, int& result) { + if (root == NULL) { + return 0; + } + + int left = dfs(root->left, result); + int right = dfs(root->right, result); + + result = max(result, left + right); + return 1 + max(left, right); + } +}; diff --git a/cpp/55-Jump-Game.cpp b/cpp/55-Jump-Game.cpp new file mode 100644 index 000000000..ad967efda --- /dev/null +++ b/cpp/55-Jump-Game.cpp @@ -0,0 +1,29 @@ +/* + Given int array, return true if can reach last index + Ex. nums = [2,3,1,1,4] -> true, index 0 to 1 to last + + Greedy: At each point, determine furthest reachable index + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + bool canJump(vector& nums) { + int n = nums.size(); + int reachable = 0; + + for (int i = 0; i < n; i++) { + if (i > reachable) { + return false; + } + reachable = max(reachable, i + nums[i]); + if (reachable >= n - 1) { + break; + } + } + + return true; + } +}; diff --git a/cpp/56-Merge-Intervals.cpp b/cpp/56-Merge-Intervals.cpp new file mode 100644 index 000000000..6bf3939f7 --- /dev/null +++ b/cpp/56-Merge-Intervals.cpp @@ -0,0 +1,39 @@ +/* + Given an array of intervals, merge all overlapping intervals + Ex. intervals = [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]] + + Sort by earliest start time, merge overlapping intervals (take longer end time) + + Time: O(n log n) + Space: O(n) +*/ + +class Solution { +public: + vector> merge(vector>& intervals) { + int n = intervals.size(); + if (n == 1) { + return intervals; + } + + sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { + return a[0] < b[0]; + }); + + vector> result; + + int i = 0; + while (i < n - 1) { + if (intervals[i][1] >= intervals[i+1][0]) { + intervals[i+1][0] = intervals[i][0]; + intervals[i+1][1] = max(intervals[i][1], intervals[i+1][1]); + } else { + result.push_back(intervals[i]); + } + i++; + } + result.push_back(intervals[i]); + + return result; + } +}; diff --git a/cpp/567-Permutation-In-String.cpp b/cpp/567-Permutation-In-String.cpp new file mode 100644 index 000000000..71046595e --- /dev/null +++ b/cpp/567-Permutation-In-String.cpp @@ -0,0 +1,48 @@ +/* + Given 2 strings, return true if s2 contains permutation of s1 + Ex. s1 = "ab", s2 = "eidbaooo" -> true, s2 contains "ba" + + Sliding window, expand + count down char, contract + count up char + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + bool checkInclusion(string s1, string s2) { + int m = s1.size(); + int n = s2.size(); + if (m > n) { + return false; + } + + vector count(26); + for (int i = 0; i < m; i++) { + count[s1[i] - 'a']++; + count[s2[i] - 'a']--; + } + if (isPermutation(count)) { + return true; + } + + for (int i = m; i < n; i++) { + count[s2[i] - 'a']--; + count[s2[i - m] - 'a']++; + if (isPermutation(count)) { + return true; + } + } + + return false; + } +private: + bool isPermutation(vector& count) { + for (int i = 0; i < 26; i++) { + if (count[i] != 0) { + return false; + } + } + return true; + } +}; diff --git a/cpp/57-Insert-Interval.cpp b/cpp/57-Insert-Interval.cpp new file mode 100644 index 000000000..cdc1cb182 --- /dev/null +++ b/cpp/57-Insert-Interval.cpp @@ -0,0 +1,38 @@ +/* + Given array of non-overlapping intervals & a new interval, insert & merge if necessary + Ex. intervals = [[1,3],[6,9]], newInterval = [2,5] -> [[1,5],[6,9]] + + To merge: while intervals are still overlapping the new one, take the larger bounds + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + vector> insert(vector>& intervals, vector& newInterval) { + int i = 0; + int n = intervals.size(); + + vector> result; + + while (i < n && intervals[i][1] < newInterval[0]) { + result.push_back(intervals[i]); + i++; + } + + while (i < n && intervals[i][0] <= newInterval[1]) { + newInterval[0] = min(newInterval[0], intervals[i][0]); + newInterval[1] = max(newInterval[1], intervals[i][1]); + i++; + } + result.push_back(newInterval); + + while (i < n) { + result.push_back(intervals[i]); + i++; + } + + return result; + } +}; diff --git a/cpp/572-Subtree-Of-Another-Tree.cpp b/cpp/572-Subtree-Of-Another-Tree.cpp new file mode 100644 index 000000000..89b79b427 --- /dev/null +++ b/cpp/572-Subtree-Of-Another-Tree.cpp @@ -0,0 +1,45 @@ +/* + Given the roots of 2 binary trees, return true if a tree has a subtree of the other tree + + Check at each node of the root tree if it's the same as the subRoot tree (structure + values) + + Time: O(m x n) + Space: O(m) +*/ + +/** + * 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 { +public: + bool isSubtree(TreeNode* root, TreeNode* subRoot) { + if (root == NULL) { + return false; + } + if (isSame(root, subRoot)) { + return true; + } + return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); + } +private: + bool isSame(TreeNode* root, TreeNode* subRoot) { + if (root == NULL && subRoot == NULL) { + return true; + } + if (root == NULL || subRoot == NULL) { + return false; + } + if (root->val != subRoot->val) { + return false; + } + return isSame(root->left, subRoot->left) && isSame(root->right, subRoot->right); + } +}; diff --git a/cpp/62-Unique-Paths.cpp b/cpp/62-Unique-Paths.cpp new file mode 100644 index 000000000..df95164c6 --- /dev/null +++ b/cpp/62-Unique-Paths.cpp @@ -0,0 +1,31 @@ +/* + Given grid, return # of unique paths from top-left to bottom-right + Ex. m = 3, n = 2 -> 3 unique paths (R->D->D, D->D->R, D->R->D) + + DP: edges have 1 unique path, inner cells consider where it comes from + Recurrence relation: grid[i][j] = grid[i-1][j] + grid[i][j-1] + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int uniquePaths(int m, int n) { + vector> grid(m, vector(n, 0)); + + for (int i = 0; i < m; i++) { + grid[i][0] = 1; + } + for (int j = 0; j < n; j++) { + grid[0][j] = 1; + } + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + grid[i][j] = grid[i - 1][j] + grid[i][j - 1]; + } + } + + return grid[m - 1][n - 1]; + } +}; diff --git a/cpp/621-Task-Scheduler.cpp b/cpp/621-Task-Scheduler.cpp new file mode 100644 index 000000000..a85588fe5 --- /dev/null +++ b/cpp/621-Task-Scheduler.cpp @@ -0,0 +1,40 @@ +/* + Given array of tasks & cooldown b/w same tasks, return least # of units of time + Ex. tasks = ["A","A","A","B","B","B"] n = 2 -> 8 (A->B->idle->A->B->idle->A->B) + + Key is to determine # of idles, greedy: always arrange task w/ most freq first + 3A, 2B, 1C -> A??A??A -> AB?AB?A -> ABCAB#A, since A most freq, needs most idles + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int leastInterval(vector& tasks, int n) { + vector counter(26); + + int maxCount = 0; + int maxCountFrequency = 0; + + for (int i = 0; i < tasks.size(); i++) { + counter[tasks[i] - 'A']++; + int currCount = counter[tasks[i] - 'A']; + + if (maxCount == currCount) { + maxCountFrequency++; + } else if (maxCount < currCount) { + maxCount = currCount; + maxCountFrequency = 1; + } + } + + int partCount = maxCount - 1; + int partLength = n - (maxCountFrequency - 1); + int emptySlots = partCount * partLength; + int availableTasks = tasks.size() - maxCount * maxCountFrequency; + int idles = max(0, emptySlots - availableTasks); + + return tasks.size() + idles; + } +}; diff --git a/cpp/647-Palindromic-Substrings.cpp b/cpp/647-Palindromic-Substrings.cpp new file mode 100644 index 000000000..a22bfd513 --- /dev/null +++ b/cpp/647-Palindromic-Substrings.cpp @@ -0,0 +1,31 @@ +/* + Given a string, return # of palindromic substrings in it + Ex. s = "babad" -> "bab", s = "cbbd" -> "bb" + + 2 pointers, middle out, check both odd & even sized strings + + Time: O(n^2) + Space: O(1) +*/ + +class Solution { +public: + int countSubstrings(string s) { + int result = 0; + + for (int i = 0; i < s.size(); i++) { + middleOut(s, i, i, result); + middleOut(s, i, i + 1, result); + } + + return result; + } +private: + void middleOut(string s, int i, int j, int& result) { + while (i >= 0 && j < s.size() && s[i] == s[j]) { + result++; + i--; + j++; + } + } +}; diff --git a/cpp/66-Plus-One.cpp b/cpp/66-Plus-One.cpp new file mode 100644 index 000000000..480f0c31e --- /dev/null +++ b/cpp/66-Plus-One.cpp @@ -0,0 +1,26 @@ +/* + Given large int as an array, add 1 (consider carry) + Ex. digits = [1,2,3] -> [1,2,4] + + From right to left, keep carrying until digit < 9, add 1 + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + vector plusOne(vector& digits) { + for (int i = digits.size() - 1; i >= 0; i--) { + if (digits[i] < 9) { + digits[i]++; + return digits; + } + digits[i] = 0; + } + + digits[0] = 1; + digits.push_back(0); + return digits; + } +}; diff --git a/cpp/684-Redundant-Connection.cpp b/cpp/684-Redundant-Connection.cpp new file mode 100644 index 000000000..14a20d716 --- /dev/null +++ b/cpp/684-Redundant-Connection.cpp @@ -0,0 +1,64 @@ +/* + Given undirected graph, return an edge that can be removed to make a tree + Ex. edges = [[1,2],[1,3],[2,3]] -> [2,3] + + If n nodes & n edges, guaranteed a cycle + How to know creating cycle? When connecting a node already connected + Union Find: can find this redundant edge, track parents & ranks + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + vector findRedundantConnection(vector>& edges) { + int n = edges.size(); + + vector parents; + vector ranks; + for (int i = 0; i < n + 1; i++) { + parents.push_back(i); + ranks.push_back(1); + + } + + vector result; + for (int i = 0; i < n; i++) { + int n1 = edges[i][0]; + int n2 = edges[i][1]; + if (!doUnion(parents, ranks, n1, n2)) { + result = {n1, n2}; + break; + } + } + return result; + } +private: + int doFind(vector& parents, int n) { + int p = parents[n]; + while (p != parents[p]) { + parents[p] = parents[parents[p]]; + p = parents[p]; + } + return p; + } + + bool doUnion(vector& parents, vector& ranks, int n1, int n2) { + int p1 = doFind(parents, n1); + int p2 = doFind(parents, n2); + if (p1 == p2) { + return false; + } + + if (ranks[p1] > ranks[p2]) { + parents[p2] = p1; + ranks[p1] += ranks[p2]; + } else { + parents[p1] = p2; + ranks[p2] += ranks[p1]; + } + + return true; + } +}; diff --git a/cpp/695-Max-Area-Of-Island.cpp b/cpp/695-Max-Area-Of-Island.cpp new file mode 100644 index 000000000..9be51dc70 --- /dev/null +++ b/cpp/695-Max-Area-Of-Island.cpp @@ -0,0 +1,38 @@ +/* + Given grid where '1' is land & '0' is water, return largest island + + DFS, set visited land to '0' to not visit it again, store biggest + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int maxAreaOfIsland(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + + int result = 0; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + result = max(result, dfs(grid, i, j, m, n)); + } + } + } + + return result; + } +private: + int dfs(vector>& grid, int i, int j, int m, int n) { + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 0) { + return 0; + } + grid[i][j] = 0; + + return 1 + dfs(grid, i - 1, j, m, n) + dfs(grid, i + 1, j, m, n) + + dfs(grid, i, j - 1, m, n) + dfs(grid, i, j + 1, m, n); + } +}; diff --git a/cpp/7-Reverse-Integer.cpp b/cpp/7-Reverse-Integer.cpp new file mode 100644 index 000000000..8486ac0a3 --- /dev/null +++ b/cpp/7-Reverse-Integer.cpp @@ -0,0 +1,28 @@ +/* + Given a signed 32-bit integer, return it with its digits reversed + Ex. x = 123 -> 321, x = -123 -> -321, x = 120 -> 21 + + Reverse bit-by-bit starting from right, shift right off every time + + Time: O(log x) + Space: O(1) +*/ + +class Solution { +public: + int reverse(int x) { + int rev = 0; + while (x != 0) { + int temp = x % 10; + x /= 10; + if (rev > INT_MAX / 10 || (rev == INT_MAX / 10 && temp > 7)) { + return 0; + } + if (rev < INT_MIN / 10 || (rev == INT_MIN / 10 && temp < -8)) { + return 0; + } + rev = rev * 10 + temp; + } + return rev; + } +}; diff --git a/cpp/70-Climbing-Stairs.cpp b/cpp/70-Climbing-Stairs.cpp new file mode 100644 index 000000000..049f2a931 --- /dev/null +++ b/cpp/70-Climbing-Stairs.cpp @@ -0,0 +1,36 @@ +/* + Climbing stairs, either 1 or 2 steps, distinct ways to reach top + Ex. n = 2 -> 2 (1 + 1, 2), n = 3 -> 3 (1 + 1 + 1, 1 + 2, 2 + 1) + + Recursion w/ memoization -> DP, why DP? Optimal substructure + Recurrence relation: dp[i] = dp[i - 1] + dp[i - 2] + Reach ith step in 2 ways: 1) 1 step from i-1, 2) 2 steps from i-2 + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int climbStairs(int n) { + if (n == 1) { + return 1; + } + if (n == 2) { + return 2; + } + + int first = 1; + int second = 2; + + int result = 0; + + for (int i = 2; i < n; i++) { + result = first + second; + first = second; + second = result; + } + + return result; + } +}; diff --git a/cpp/703-Kth-Largest-Element-In-A-Stream.cpp b/cpp/703-Kth-Largest-Element-In-A-Stream.cpp new file mode 100644 index 000000000..aef3e8f2e --- /dev/null +++ b/cpp/703-Kth-Largest-Element-In-A-Stream.cpp @@ -0,0 +1,39 @@ +/* + Design a class to find the kth largest element in a stream + + Min heap & maintain only k elements, top will always be kth largest + Ex. nums = [6,2,3,1,7], k = 3 -> [1,2,3,6,7] -> [3,6,7] + + Time: O(n log n + m log k) -> n = length of nums, m = add calls + Space: O(n) +*/ + +class KthLargest { +public: + KthLargest(int k, vector& nums) { + this->k = k; + for (int i = 0; i < nums.size(); i++) { + pq.push(nums[i]); + } + while (pq.size() > this->k) { + pq.pop(); + } + } + + int add(int val) { + pq.push(val); + if (pq.size() > k) { + pq.pop(); + } + return pq.top(); + } +private: + int k; + priority_queue, greater> pq; +}; + +/** + * Your KthLargest object will be instantiated and called as such: + * KthLargest* obj = new KthLargest(k, nums); + * int param_1 = obj->add(val); + */ diff --git a/cpp/704-Binary-Search.cpp b/cpp/704-Binary-Search.cpp new file mode 100644 index 000000000..eef59c8d8 --- /dev/null +++ b/cpp/704-Binary-Search.cpp @@ -0,0 +1,30 @@ +/* + Given sorted int array, search for a target value + Ex. nums = [-1,0,3,5,9,12], target = 9 -> 4 (index) + + Since array is sorted, perform binary search + + Time: O(log n) + Space: O(1) +*/ + +class Solution { +public: + int search(vector& nums, int target) { + int low = 0; + int high = nums.size() - 1; + + while (low <= high) { + int mid = low + (high - low) / 2; + if (nums[mid] < target) { + low = mid + 1; + } else if (nums[mid] > target) { + high = mid - 1; + } else { + return mid; + } + } + + return -1; + } +}; diff --git a/cpp/72-Edit-Distance.cpp b/cpp/72-Edit-Distance.cpp new file mode 100644 index 000000000..46e9290b5 --- /dev/null +++ b/cpp/72-Edit-Distance.cpp @@ -0,0 +1,77 @@ +/* + Given 2 strings, return minimum number of operations to convert word1 to word2 + + Naive: check all possible edit sequences & choose shortest one + Optimal: DP, if chars at i & j same, no operations needed, else 3 cases: + (1) replace (i - 1, j - 1), (2) delete (i - 1, j), (3) insert (i, j - 1) + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int minDistance(string word1, string word2) { + if (word1.empty() && word2.empty()) { + return 0; + } + if (word1.empty() || word2.empty()) { + return 1; + } + + int m = word1.size(); + int n = word2.size(); + + vector> dp(m + 1, vector(n + 1)); + + // base cases (convert to empty string w/ deletions), dist is just length + for (int i = 1; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 1; j <= n; j++) { + dp[0][j] = j; + } + + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (word1[i - 1] == word2[j - 1]) { + // no operation needed, same char + dp[i][j] = dp[i - 1][j - 1]; + } else { + // min(replace, delete, insert) + 1 <-- since an op was needed + dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1; + } + } + } + + return dp[m][n]; + } +}; + +// Since we only need at most dp[i - 1][j - 1], can space optimize to O(n) +// class Solution { +// public: +// int minDistance(string word1, string word2) { +// int m = word1.size(); +// int n = word2.size(); +// int prev = 0; +// vector curr(n + 1); +// for (int j = 1; j <= n; j++) { +// curr[j] = j; +// } +// for (int i = 1; i <= m; i++) { +// prev = curr[0]; +// curr[0] = i; +// for (int j = 1; j <= n; j++) { +// int temp = curr[j]; +// if (word1[i - 1] == word2[j - 1]) { +// curr[j] = prev; +// } else { +// curr[j] = min(prev, min(curr[j - 1], curr[j])) + 1; +// } +// prev = temp; +// } +// } +// return curr[n]; +// } +// }; diff --git a/cpp/73-Set-Matrix-Zeroes.cpp b/cpp/73-Set-Matrix-Zeroes.cpp new file mode 100644 index 000000000..b8f3d4e44 --- /dev/null +++ b/cpp/73-Set-Matrix-Zeroes.cpp @@ -0,0 +1,62 @@ +/* + Given matrix, if element 0, set entire row/col to 0 + + Use 1st row/col as flag to determine if entire row/col 0 + + Time: O(mn) + Space: O(1) +*/ + +class Solution { +public: + void setZeroes(vector>& matrix) { + int m = matrix.size(); + int n = matrix[0].size(); + + bool isFirstRowZero = false; + bool isFirstColZero = false; + + for (int i = 0; i < m; i++) { + if (matrix[i][0] == 0) { + isFirstColZero = true; + break; + } + } + + for (int j = 0; j < n; j++) { + if (matrix[0][j] == 0) { + isFirstRowZero = true; + break; + } + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + if (matrix[i][j] == 0) { + matrix[i][0] = 0; + matrix[0][j] = 0; + } + } + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + if (matrix[i][0] == 0 || matrix[0][j] == 0) { + matrix[i][j] = 0; + } + } + } + + if (isFirstColZero) { + for (int i = 0; i < m; i++) { + matrix[i][0] = 0; + } + } + + if (isFirstRowZero) { + for (int j = 0; j < n; j++) { + matrix[0][j] = 0; + } + } + } +}; diff --git a/cpp/739-Daily-Temperatures.cpp b/cpp/739-Daily-Temperatures.cpp new file mode 100644 index 000000000..e3d273b30 --- /dev/null +++ b/cpp/739-Daily-Temperatures.cpp @@ -0,0 +1,37 @@ +/* + Given array of temps, return an array w/ # of days until warmer + Ex. temperature = [73,74,75,71,69,72,76,73] -> [1,1,4,2,1,1,0,0] + + Monotonic decr stack, at each day, compare incr from prev days + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + vector dailyTemperatures(vector& temperatures) { + int n = temperatures.size(); + + // pair: [index, temp] + stack> stk; + vector result(n); + + for (int i = 0; i < n; i++) { + int currDay = i; + int currTemp = temperatures[i]; + + while (!stk.empty() && stk.top().second < currTemp) { + int prevDay = stk.top().first; + int prevTemp = stk.top().second; + stk.pop(); + + result[prevDay] = currDay - prevDay; + } + + stk.push({currDay, currTemp}); + } + + return result; + } +}; diff --git a/cpp/74-Search-A-2d-Matrix.cpp b/cpp/74-Search-A-2d-Matrix.cpp new file mode 100644 index 000000000..5a1ddd529 --- /dev/null +++ b/cpp/74-Search-A-2d-Matrix.cpp @@ -0,0 +1,49 @@ +/* + Search for target value in matrix where every row & col is sorted + + Perform 2 binary searches: 1 to find row, then another to find col + + Time: O(log m + log n) + Space: O(1) +*/ + +class Solution { +public: + bool searchMatrix(vector>& matrix, int target) { + int lowRow = 0; + int highRow = matrix.size() - 1; + + while (lowRow < highRow) { + int mid = lowRow + (highRow - lowRow) / 2; + if (matrix[mid][0] == target) { + return true; + } + if (matrix[mid][0] < target && target < matrix[mid + 1][0]) { + lowRow = mid; + break; + } + if (matrix[mid][0] < target) { + lowRow = mid + 1; + } else { + highRow = mid - 1; + } + } + + int lowCol = 0; + int highCol = matrix[0].size() - 1; + + while (lowCol <= highCol) { + int mid = lowCol + (highCol - lowCol) / 2; + if (matrix[lowRow][mid] == target) { + return true; + } + if (matrix[lowRow][mid] < target) { + lowCol = mid + 1; + } else { + highCol = mid - 1; + } + } + + return false; + } +}; diff --git a/cpp/743-Network-Delay-Time.cpp b/cpp/743-Network-Delay-Time.cpp new file mode 100644 index 000000000..0e80ee662 --- /dev/null +++ b/cpp/743-Network-Delay-Time.cpp @@ -0,0 +1,63 @@ +/* + Signal sent from node k to network of n nodes, return time for all nodes to receive it + Ex. times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2 -> 2 + u,v,w -> u = source node, v = target node, w = signal travel time + + Shortest path from node k to every other node, Dijkstra's to find fastest path + + Time: O(V + E log V) + Space: O(V + E) +*/ + +class Solution { +public: + int networkDelayTime(vector>& times, int n, int k) { + vector> adj[n + 1]; + for (int i = 0; i < times.size(); i++) { + int source = times[i][0]; + int dest = times[i][1]; + int time = times[i][2]; + adj[source].push_back({time, dest}); + } + + vector signalReceiveTime(n + 1, INT_MAX); + priority_queue, vector>, greater>> pq; + pq.push({0, k}); + + // time for start node is 0 + signalReceiveTime[k] = 0; + + while (!pq.empty()) { + int currNodeTime = pq.top().first; + int currNode = pq.top().second; + pq.pop(); + + if (currNodeTime > signalReceiveTime[currNode]) { + continue; + } + + // send signal to adjacent nodes + for (int i = 0; i < adj[currNode].size(); i++) { + pair edge = adj[currNode][i]; + int time = edge.first; + int neighborNode = edge.second; + + // fastest signal time for neighborNode so far + if (signalReceiveTime[neighborNode] > currNodeTime + time) { + signalReceiveTime[neighborNode] = currNodeTime + time; + pq.push({signalReceiveTime[neighborNode], neighborNode}); + } + } + } + + int result = INT_MIN; + for (int i = 1; i <= n; i++) { + result = max(result, signalReceiveTime[i]); + } + + if (result == INT_MAX) { + return -1; + } + return result; + } +}; diff --git a/cpp/746-Min-Cost-Climbing-Stairs.cpp b/cpp/746-Min-Cost-Climbing-Stairs.cpp new file mode 100644 index 000000000..f2adde947 --- /dev/null +++ b/cpp/746-Min-Cost-Climbing-Stairs.cpp @@ -0,0 +1,27 @@ +/* + Given cost array, ith step is cost[i], can climb 1 or 2 steps + Return min cost to reach top floor, can start at index 0 or 1 + Ex. cost = [10,15,20] -> 15, start at idx 1, pay 15, climb 2 + + Recursion w/ memoization -> DP, min cost to reach 1/2 steps below curr step + Recurrence relation: minCost[i] = min(minCost[i-1] + cost[i-1], minCost[i-2] + cost[i-2]) + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + int minCostClimbingStairs(vector& cost) { + int downOne = 0; + int downTwo = 0; + + for (int i = 2; i <= cost.size(); i++) { + int temp = downOne; + downOne = min(downOne + cost[i - 1], downTwo + cost[i - 2]); + downTwo = temp; + } + + return downOne; + } +}; diff --git a/cpp/76-Minimum-Window-Substring.cpp b/cpp/76-Minimum-Window-Substring.cpp new file mode 100644 index 000000000..14eb516f4 --- /dev/null +++ b/cpp/76-Minimum-Window-Substring.cpp @@ -0,0 +1,62 @@ +/* + Given 2 strings s & t, return min window substring + of s such that all chars in t are included in window + Ex. s = "ADOBECODEBANC" t = "ABC" -> "BANC" + + Sliding window + hash map {char -> count} + Move j until valid, move i to find smaller + + Time: O(m + n) + Space: O(m + n) +*/ + +class Solution { +public: + string minWindow(string s, string t) { + // count of char in t + unordered_map m; + for (int i = 0; i < t.size(); i++) { + m[t[i]]++; + } + + int i = 0; + int j = 0; + + // # of chars in t that must be in s + int counter = t.size(); + + int minStart = 0; + int minLength = INT_MAX; + + while (j < s.size()) { + // if char in s exists in t, decrease + if (m[s[j]] > 0) { + counter--; + } + // if char doesn't exist in t, will be -'ve + m[s[j]]--; + // move j to find valid window + j++; + + // when window found, move i to find smaller + while (counter == 0) { + if (j - i < minLength) { + minStart = i; + minLength = j - i; + } + + m[s[i]]++; + // when char exists in t, increase + if (m[s[i]] > 0) { + counter++; + } + i++; + } + } + + if (minLength != INT_MAX) { + return s.substr(minStart, minLength); + } + return ""; + } +}; diff --git a/cpp/763-Partition-Labels.cpp b/cpp/763-Partition-Labels.cpp new file mode 100644 index 000000000..ed728297a --- /dev/null +++ b/cpp/763-Partition-Labels.cpp @@ -0,0 +1,38 @@ +/* + Partition string so each letter appears in at most 1 part, return sizes + Ex. s = "ababcbacadefegdehijhklij" -> [9,7,8] + + Greedy: determine last occurrence of each char, then loop thru & get sizes + + Time: O(n) + Space: O(1) +*/ + +class Solution { +public: + vector partitionLabels(string s) { + int n = s.size(); + // {char -> last index in s} + vector lastIndex(26); + for (int i = 0; i < n; i++) { + lastIndex[s[i] - 'a'] = i; + } + + int size = 0; + int end = 0; + + vector result; + + for (int i = 0; i < n; i++) { + size++; + // constantly checking for further indices if possible + end = max(end, lastIndex[s[i] - 'a']); + if (i == end) { + result.push_back(size); + size = 0; + } + } + + return result; + } +}; diff --git a/cpp/778-Swim-In-Rising-Water.cpp b/cpp/778-Swim-In-Rising-Water.cpp new file mode 100644 index 000000000..7ad10d9a0 --- /dev/null +++ b/cpp/778-Swim-In-Rising-Water.cpp @@ -0,0 +1,54 @@ +/* + Given an integer elevation matrix, rain falls, at time t, depth everywhere is t + Can swim iff elevation at most t, return least time get from top left to bottom right + + Shortest path w/ min heap: at every step, find lowest water level to move forward + + Time: O(n^2 log n) + Space: O(n^2) +*/ + +class Solution { +public: + int swimInWater(vector>& grid) { + int n = grid.size(); + if (n == 1) { + return 0; + } + + vector> visited(n, vector(n)); + visited[0][0] = true; + + int result = max(grid[0][0], grid[n - 1][n - 1]); + + priority_queue, vector>, greater>> pq; + pq.push({result, 0, 0}); + + while (!pq.empty()) { + vector curr = pq.top(); + pq.pop(); + + result = max(result, curr[0]); + + for (int i = 0; i < 4; i++) { + int x = curr[1] + dirs[i][0]; + int y = curr[2] + dirs[i][1]; + + if (x < 0 || x >= n || y < 0 || y >= n || visited[x][y]) { + continue; + } + + if (x == n - 1 && y == n - 1) { + return result; + } + + pq.push({grid[x][y], x, y}); + visited[x][y] = true; + } + } + + return -1; + } +private: + vector> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; +}; diff --git a/cpp/78-Subsets.cpp b/cpp/78-Subsets.cpp new file mode 100644 index 000000000..dee1eab47 --- /dev/null +++ b/cpp/78-Subsets.cpp @@ -0,0 +1,28 @@ +/* + Given an integer array of unique elements, return all possible subsets (the power set) + Ex. nums = [1,2,3] -> [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] + + Backtracking, generate all combinations, push/pop + index checking to explore new combos + + Time: O(n x 2^n) + Space: O(n) +*/ + +class Solution { +public: + vector> subsets(vector& nums) { + vector curr; + vector> result; + dfs(nums, 0, curr, result); + return result; + } +private: + void dfs(vector& nums, int start, vector& curr, vector>& result) { + result.push_back(curr); + for (int i = start; i < nums.size(); i++) { + curr.push_back(nums[i]); + dfs(nums, i + 1, curr, result); + curr.pop_back(); + } + } +}; diff --git a/cpp/787-Cheapest-Flights-Within-K-Stops.cpp b/cpp/787-Cheapest-Flights-Within-K-Stops.cpp new file mode 100644 index 000000000..ab62525ff --- /dev/null +++ b/cpp/787-Cheapest-Flights-Within-K-Stops.cpp @@ -0,0 +1,78 @@ +/* + Given cities connected by flights [from,to,price], also given src, dst, & k: + Return cheapest price from src to dst with at most k stops + + Dijkstra's but modified, normal won't work b/c will discard heap nodes w/o finishing + Modify: need to re-consider a node if dist from source is shorter than what we recorded + But, if we encounter node already processed but # of stops from source is lesser, + Need to add it back to the heap to be considered again + + Time: O(V^2 log V) -> V = number of cities + Space: O(V^2) +*/ + +class Solution { +public: + int findCheapestPrice(int n, vector>& flights, int src, int dst, int k) { + // build adjacency matrix + vector> adj(n, vector(n)); + for (int i = 0; i < flights.size(); i++) { + vector flight = flights[i]; + adj[flight[0]][flight[1]] = flight[2]; + } + + // shortest distances + vector distances(n, INT_MAX); + distances[src] = 0; + // shortest steps + vector currStops(n, INT_MAX); + currStops[src] = 0; + + // priority queue -> (cost, node, stops) + priority_queue, vector>, greater>> pq; + pq.push({0, src, 0}); + + while (!pq.empty()) { + int cost = pq.top()[0]; + int node = pq.top()[1]; + int stops = pq.top()[2]; + pq.pop(); + + // if destination is reached, return cost to get here + if (node == dst) { + return cost; + } + + // if no more steps left, continue + if (stops == k + 1) { + continue; + } + + // check & relax all neighboring edges + for (int neighbor = 0; neighbor < n; neighbor++) { + if (adj[node][neighbor] > 0) { + int currCost = cost; + int neighborDist = distances[neighbor]; + int neighborWeight = adj[node][neighbor]; + + // check if better cost + int currDist = currCost + neighborWeight; + if (currDist < neighborDist || stops + 1 < currStops[neighbor]) { + pq.push({currDist, neighbor, stops + 1}); + distances[neighbor] = currDist; + currStops[neighbor] = stops; + } else if (stops < currStops[neighbor]) { + // check if better steps + pq.push({currDist, neighbor, stops + 1}); + } + currStops[neighbor] = stops; + } + } + } + + if (distances[dst] == INT_MAX) { + return -1; + } + return distances[dst]; + } +}; diff --git a/cpp/79-Word-Search.cpp b/cpp/79-Word-Search.cpp new file mode 100644 index 000000000..09a5fd102 --- /dev/null +++ b/cpp/79-Word-Search.cpp @@ -0,0 +1,51 @@ +/* + Given a char board & a word, return true if word exists in the grid + + DFS traversal, set visited cells to '#', search in 4 directions, backtrack + + Time: O(n x 3^l) -> n = # of cells, l = length of word + Space: O(l) +*/ + +class Solution { +public: + bool exist(vector>& board, string word) { + int m = board.size(); + int n = board[0].size(); + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == word[0]) { + if (dfs(board, word, 0, i, j, m, n)) { + return true; + } + } + } + } + + return false; + } +private: + bool dfs(vector>& board, string word, + int index, int i, int j, int m, int n) { + + if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] != word[index]) { + return false; + } + if (index == word.size() - 1) { + return true; + } + + board[i][j] = '#'; + + if (dfs(board, word, index + 1, i - 1, j, m, n) + || dfs(board, word, index + 1, i + 1, j, m, n) + || dfs(board, word, index + 1, i, j - 1, m, n) + || dfs(board, word, index + 1, i, j + 1, m, n)) { + return true; + } + + board[i][j] = word[index]; + return false; + } +}; diff --git a/cpp/84-Largest-Rectangle-In-Histogram.cpp b/cpp/84-Largest-Rectangle-In-Histogram.cpp new file mode 100644 index 000000000..642ed6eac --- /dev/null +++ b/cpp/84-Largest-Rectangle-In-Histogram.cpp @@ -0,0 +1,44 @@ +/* +Given array of heights, return area of largest rectangle +Ex. heights = [2,1,5,6,2,3] -> 10 (5 x 2 at index 2 and 3) + +Monotonic incr stack, if curr height lower extend back, find max area + +Time: O(n) +Space: O(n) +*/ + +class Solution { +public: + int largestRectangleArea(vector& heights) { + // pair: [index, height] + stack> stk; + int result = 0; + + for (int i = 0; i < heights.size(); i++) { + int start = i; + + while (!stk.empty() && stk.top().second > heights[i]) { + int index = stk.top().first; + int width = i - index; + int height = stk.top().second; + stk.pop(); + + result = max(result, height * width); + start = index; + } + + stk.push({start, heights[i]}); + } + + while (!stk.empty()) { + int width = heights.size() - stk.top().first; + int height = stk.top().second; + stk.pop(); + + result = max(result, height * width); + } + + return result; + } +}; diff --git a/cpp/846-Hand-Of-Straights.cpp b/cpp/846-Hand-Of-Straights.cpp new file mode 100644 index 000000000..f237e9b05 --- /dev/null +++ b/cpp/846-Hand-Of-Straights.cpp @@ -0,0 +1,41 @@ +/* + Given int array, return true if can rearrange cards into groupSize consecutive + Ex. hand = [1,2,3,6,2,3,4,7,8], groupSize = 3 -> true, [1,2,3],[2,3,4],[6,7,8] + + Loop thru ordered map, for a value, check groupSize consecutive & remove + + Time: O(n log n) + Space: O(n) +*/ + +class Solution { +public: + bool isNStraightHand(vector& hand, int groupSize) { + int n = hand.size(); + + if (n % groupSize != 0) { + return false; + } + + // map {card value -> count} + map m; + for (int i = 0; i < n; i++) { + m[hand[i]]++; + } + + while (!m.empty()) { + int curr = m.begin()->first; + for (int i = 0; i < groupSize; i++) { + if (m[curr + i] == 0) { + return false; + } + m[curr + i]--; + if (m[curr + i] < 1) { + m.erase(curr + i); + } + } + } + + return true; + } +}; diff --git a/cpp/853-Car-Fleet.cpp b/cpp/853-Car-Fleet.cpp new file mode 100644 index 000000000..679806513 --- /dev/null +++ b/cpp/853-Car-Fleet.cpp @@ -0,0 +1,37 @@ +/* + n cars 1 road, diff pos/speeds, faster cars slow down -> car fleet, return # fleets + Ex. target = 12, pos = [10,8,0,5,3], speeds = [2,4,1,1,3] -> 3 (10 & 8, 0, 5 & 3) + + Sort by start pos, calculate time for each car to finish, loop backwards + If car behind finishes faster then catches up to fleet, else creates new fleet + + Time: O(n log n) + Speed: O(n) +*/ + +class Solution { +public: + int carFleet(int target, vector& position, vector& speed) { + int n = position.size(); + + vector> cars; + for (int i = 0; i < n; i++) { + double time = (double) (target - position[i]) / speed[i]; + cars.push_back({position[i], time}); + } + sort(cars.begin(), cars.end()); + + double maxTime = 0.0; + int result = 0; + + for (int i = n - 1; i >= 0; i--) { + double time = cars[i].second; + if (time > maxTime) { + maxTime = time; + result++; + } + } + + return result; + } +}; diff --git a/cpp/875-Koko-Eating-Bananas.cpp b/cpp/875-Koko-Eating-Bananas.cpp new file mode 100644 index 000000000..b7116cbbf --- /dev/null +++ b/cpp/875-Koko-Eating-Bananas.cpp @@ -0,0 +1,41 @@ +/* + Given array of banana piles, guards are gone for h hours + Return min int k such that can eat all banans within h + Ex. piles = [3,6,7,11] h = 8 -> 4 (1@3, 2@6, 2@7, 3@11) + + Binary search, for each k count hours needed, store min + + Time: O(n x log m) -> n = # of piles, m = max # in a pile + Space: O(1) +*/ + +class Solution { +public: + int minEatingSpeed(vector& piles, int h) { + int n = piles.size(); + + int low = 1; + int high = 0; + for (int i = 0; i < n; i++) { + high = max(high, piles[i]); + } + + int result = high; + + while (low <= high) { + int k = low + (high - low) / 2; + long int hours = 0; + for (int i = 0; i < n; i++) { + hours += ceil((double) piles[i] / k); + } + if (hours <= h) { + result = min(result, k); + high = k - 1; + } else { + low = k + 1; + } + } + + return result; + } +}; diff --git a/cpp/875-Koko-Eating-Bananas.cpp-Hand-Of-Straights.cpp b/cpp/875-Koko-Eating-Bananas.cpp-Hand-Of-Straights.cpp new file mode 100644 index 000000000..b7116cbbf --- /dev/null +++ b/cpp/875-Koko-Eating-Bananas.cpp-Hand-Of-Straights.cpp @@ -0,0 +1,41 @@ +/* + Given array of banana piles, guards are gone for h hours + Return min int k such that can eat all banans within h + Ex. piles = [3,6,7,11] h = 8 -> 4 (1@3, 2@6, 2@7, 3@11) + + Binary search, for each k count hours needed, store min + + Time: O(n x log m) -> n = # of piles, m = max # in a pile + Space: O(1) +*/ + +class Solution { +public: + int minEatingSpeed(vector& piles, int h) { + int n = piles.size(); + + int low = 1; + int high = 0; + for (int i = 0; i < n; i++) { + high = max(high, piles[i]); + } + + int result = high; + + while (low <= high) { + int k = low + (high - low) / 2; + long int hours = 0; + for (int i = 0; i < n; i++) { + hours += ceil((double) piles[i] / k); + } + if (hours <= h) { + result = min(result, k); + high = k - 1; + } else { + low = k + 1; + } + } + + return result; + } +}; diff --git a/cpp/90-Subsets-II.cpp b/cpp/90-Subsets-II.cpp new file mode 100644 index 000000000..c923dad51 --- /dev/null +++ b/cpp/90-Subsets-II.cpp @@ -0,0 +1,34 @@ +/* + Given an integer array of unique elements, return all possible subsets (the power set) + Ex. nums = [1,2,2] -> [[],[1],[1,2],[1,2,2],[2],[2,2]] + + Backtracking, generate all combos, push/pop + to explore new combos, skip duplicates + + Time: O(n x 2^n) + Space: O(n) +*/ + +class Solution { +public: + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(), nums.end()); + + vector curr; + vector> result; + + dfs(nums, 0, curr, result); + return result; + } +private: + void dfs(vector& nums, int start, vector& curr, vector>& result) { + result.push_back(curr); + for (int i = start; i < nums.size(); i++) { + if (i > start && nums[i] == nums[i - 1]) { + continue; + } + curr.push_back(nums[i]); + dfs(nums, i + 1, curr, result); + curr.pop_back(); + } + } +}; diff --git a/cpp/91-Decode-Ways.cpp b/cpp/91-Decode-Ways.cpp new file mode 100644 index 000000000..385bf81ae --- /dev/null +++ b/cpp/91-Decode-Ways.cpp @@ -0,0 +1,38 @@ +/* + Given a string w/ only digits, return # ways to decode it (letter -> digit) + Ex. s = "12" -> 2 (AB 1 2 or L 12), s = "226" -> 3 (2 26 or 22 6 or 2 2 6) + + DP: At each digit, check validity of ones & tens, if valid add to # ways + Recurrence relation: dp[i] += dp[i-1] (if valid) + dp[i-2] (if valid) + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + int numDecodings(string s) { + if (s[0] == '0') { + return 0; + } + + int n = s.size(); + + vector dp(n + 1); + dp[0] = 1; + dp[1] = 1; + + for (int i = 2; i <= n; i++) { + int ones = stoi(s.substr(i - 1, 1)); + if (ones >= 1 && ones <= 9) { + dp[i] += dp[i - 1]; + } + int tens = stoi(s.substr(i - 2, 2)); + if (tens >= 10 && tens <= 26) { + dp[i] += dp[i - 2]; + } + } + + return dp[n]; + } +}; diff --git a/cpp/953-Alien-Dictionary.cpp b/cpp/953-Alien-Dictionary.cpp new file mode 100644 index 000000000..f53991334 --- /dev/null +++ b/cpp/953-Alien-Dictionary.cpp @@ -0,0 +1,99 @@ +/* + Given list of words in another language, return string such that: + Letters are sorted in lexicographical incr order wrt this language + Ex. words = ["wrt","wrf","er","ett","rftt"] + + Build graph + record edges, BFS + topological sort, check cyclic + + Time: O(n) + Space: O(n) +*/ + +class Solution { +public: + string alienOrder(vector &words) { + + unordered_map> graph; + unordered_map indegree; + + // indegree make all char 0 + for(auto word : words){ + for(auto c : st){ + indegree[c]=0; + } + } + + for(int i=0; i set; + + if(graph.find(ch1) != graph.end()){ + set = graph[ch1]; + + if(set.find(ch2) == set.end()){ + set.insert(ch2); + indegree[ch2]++; + graph[ch1] = set; + } + } + else{ + set.insert(ch2); + indegree[ch2]++; + graph[ch1] = set; + } + + flag = true; + break; + } + + } + + if(flag == false and (curr.length() > next.length())) return ""; + } + + priority_queue, greater> q; + + for(auto it : indegree){ + if(it.second == 0){ + //cout<0){ + auto rem = q.top(); + q.pop(); + + ans += rem; + count++; + + if(graph.find(rem) != graph.end()){ + unordered_set nbrs = graph[rem]; + + for(auto nbr : nbrs){ + indegree[nbr]--; + if(indegree[nbr] == 0){ + q.push(nbr); + } + } + } + } + + if(count == indegree.size()){ + return ans; + } + return ""; + } +}; diff --git a/cpp/97-Interleaving-String.cpp b/cpp/97-Interleaving-String.cpp new file mode 100644 index 000000000..26f936c64 --- /dev/null +++ b/cpp/97-Interleaving-String.cpp @@ -0,0 +1,41 @@ +/* + Given 3 strings, find if s3 is formed by interleaving of s1 & s2 + Ex. s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" -> true + + DFS + memo, cache on s1 & s2 indices i & j + 2 choices: either take s1 & iterate i, or take s2 & iterate j + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + bool isInterleave(string s1, string s2, string s3) { + if (s3.size() != s1.size() + s2.size()) { + return false; + } + return dfs(s1, s2, s3, 0, 0); + } +private: + map, bool> dp; + + bool dfs(string s1, string s2, string s3, int i, int j) { + if (i == s1.size() && j == s2.size()) { + return true; + } + if (dp.find({i, j}) != dp.end()) { + return dp[{i, j}]; + } + + if (i < s1.size() && s1[i] == s3[i + j] && dfs(s1, s2, s3, i + 1, j)) { + return true; + } + if (j < s2.size() && s2[j] == s3[i + j] && dfs(s1, s2, s3, i, j + 1)) { + return true; + } + + dp[{i, j}] = false; + return dp[{i, j}]; + } +}; diff --git a/cpp/973-K-Closest-Points-To-Origin.cpp b/cpp/973-K-Closest-Points-To-Origin.cpp new file mode 100644 index 000000000..469f37ab5 --- /dev/null +++ b/cpp/973-K-Closest-Points-To-Origin.cpp @@ -0,0 +1,74 @@ +/* + Given array of points & an int k, return k closest points to (0, 0) + Ex. points = [[1,3],[-2,2]], k = 1 -> [[-2,2]] + + Quickselect, partition until pivot = k, left side all < k + + Time: O(n) -> optimized from O(n log k) max heap solution + Space: O(1) +*/ + +// class Solution { +// public: +// vector> kClosest(vector>& points, int k) { +// priority_queue>> pq; +// for (int i = 0; i < points.size(); i++) { +// double distance = sqrt(pow(points[i][0], 2) + pow(points[i][1], 2)); +// pq.push({distance, points[i]}); +// if (pq.size() > k) { +// pq.pop(); +// } +// } + +// vector> result; +// while(!pq.empty()) { +// result.push_back(pq.top().second); +// pq.pop(); +// } + +// return result; +// } +// }; + +class Solution { +public: + vector> kClosest(vector>& points, int k) { + int low = 0; + int high = points.size() - 1; + int pivotIndex = points.size(); + + while (pivotIndex != k) { + pivotIndex = partition(points, low, high); + if (pivotIndex < k) { + low = pivotIndex; + } else { + high = pivotIndex - 1; + } + } + + return vector>(points.begin(), points.begin() + k); + } +private: + int partition(vector>& points, int low, int high) { + vector pivot = points[low + (high - low) / 2]; + int pivotDistance = getDistance(pivot); + + while (low < high) { + if (getDistance(points[low]) >= pivotDistance) { + swap(points[low], points[high]); + high--; + } else { + low++; + } + } + + if (getDistance(points[low]) < pivotDistance) { + low++; + } + return low; + } + + int getDistance(vector& point) { + return pow(point[0], 2) + pow(point[1], 2); + } +}; diff --git a/cpp/98-Validate-Binary-Search-Tree.cpp b/cpp/98-Validate-Binary-Search-Tree.cpp new file mode 100644 index 000000000..fff6a992b --- /dev/null +++ b/cpp/98-Validate-Binary-Search-Tree.cpp @@ -0,0 +1,74 @@ +/* + Given root of binary tree, determine if it's valid (left all < curr, right all > curr) + + Inorder traversal & check if prev >= curr, recursive/iterative solutions + + Time: O(n) + Space: O(n) +*/ + +/** + * 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 { +public: + bool isValidBST(TreeNode* root) { + TreeNode* prev = NULL; + return inorder(root, prev); + } +private: + bool inorder(TreeNode* root, TreeNode*& prev) { + if (root == NULL) { + return true; + } + + if (!inorder(root->left, prev)) { + return false; + } + + if (prev != NULL && prev->val >= root->val) { + return false; + } + prev = root; + + if (!inorder(root->right, prev)) { + return false; + } + + return true; + } +}; + +// class Solution { +// public: +// bool isValidBST(TreeNode* root) { +// stack stk; +// TreeNode* prev = NULL; + +// while (!stk.empty() || root != NULL) { +// while (root != NULL) { +// stk.push(root); +// root = root->left; +// } +// root = stk.top(); +// stk.pop(); + +// if (prev != NULL && prev->val >= root->val) { +// return false; +// } + +// prev = root; +// root = root->right; +// } + +// return true; +// } +// }; diff --git a/cpp/981-Time-Based-Key-Value-Store.cpp b/cpp/981-Time-Based-Key-Value-Store.cpp new file mode 100644 index 000000000..b82391423 --- /dev/null +++ b/cpp/981-Time-Based-Key-Value-Store.cpp @@ -0,0 +1,53 @@ +/* + Design time-based key-value structure, multiple vals at diff times + + Hash map, since timestamps are naturally in order, binary search + + Time: O(log n) + Space: O(n) +*/ + +class TimeMap { +public: + TimeMap() { + + } + + void set(string key, string value, int timestamp) { + m[key].push_back({timestamp, value}); + } + + string get(string key, int timestamp) { + if (m.find(key) == m.end()) { + return ""; + } + + int low = 0; + int high = m[key].size() - 1; + + while (low <= high) { + int mid = low + (high - low) / 2; + if (m[key][mid].first < timestamp) { + low = mid + 1; + } else if (m[key][mid].first > timestamp) { + high = mid - 1; + } else { + return m[key][mid].second; + } + } + + if (high >= 0) { + return m[key][high].second; + } + return ""; + } +private: + unordered_map>> m; +}; + +/** + * Your TimeMap object will be instantiated and called as such: + * TimeMap* obj = new TimeMap(); + * obj->set(key,value,timestamp); + * string param_2 = obj->get(key,timestamp); + */ diff --git a/cpp/994-Rotting-Oranges.cpp b/cpp/994-Rotting-Oranges.cpp new file mode 100644 index 000000000..b6ea6e00f --- /dev/null +++ b/cpp/994-Rotting-Oranges.cpp @@ -0,0 +1,74 @@ +/* + Given grid: 0 empty cell, 1 fresh orange, 2 rotten orange + Return min # of minutes until no cell has a fresh orange + + BFS: rotten will contaminate neighbors first, then propagate out + + Time: O(m x n) + Space: O(m x n) +*/ + +class Solution { +public: + int orangesRotting(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + + // build initial set of rotten oranges + queue> q; + int fresh = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 2) { + q.push({i, j}); + } else if (grid[i][j] == 1) { + fresh++; + } + } + } + // mark the start of a minute + q.push({-1, -1}); + + int result = -1; + + // start rotting process via BFS + while (!q.empty()) { + int row = q.front().first; + int col = q.front().second; + q.pop(); + + if (row == -1) { + // finish 1 minute of processing, mark next minute + result++; + if (!q.empty()) { + q.push({-1, -1}); + } + } else { + // rotten orange, contaminate its neighbors + for (int i = 0; i < dirs.size(); i++) { + int x = row + dirs[i][0]; + int y = col + dirs[i][1]; + + if (x < 0 || x >= m || y < 0 || y >= n) { + continue; + } + + if (grid[x][y] == 1) { + // contaminate + grid[x][y] = 2; + fresh--; + // this orange will now contaminate others + q.push({x, y}); + } + } + } + } + + if (fresh == 0) { + return result; + } + return -1; + } +private: + vector> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; +};