diff --git a/articles/binary-tree-inorder-traversal.md b/articles/binary-tree-inorder-traversal.md new file mode 100644 index 000000000..4735f8400 --- /dev/null +++ b/articles/binary-tree-inorder-traversal.md @@ -0,0 +1,467 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + + def inorder(node): + if not node: + return + + inorder(node.left) + res.append(node.val) + inorder(node.right) + + inorder(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private List res; + + public List inorderTraversal(TreeNode root) { + res = new ArrayList<>(); + inorder(root); + return res; + } + + private void inorder(TreeNode node) { + if (node == null) { + return; + } + inorder(node.left); + res.add(node.val); + inorder(node.right); + } +} +``` + +```cpp +/** + * 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 { + vector res; + +public: + vector inorderTraversal(TreeNode* root) { + inorder(root); + return res; + } + +private: + void inorder(TreeNode* node) { + if (!node) { + return; + } + inorder(node->left); + res.push_back(node->val); + inorder(node->right); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + inorderTraversal(root) { + const res = []; + + const inorder = (node) => { + if (!node) return; + inorder(node.left); + res.push(node.val); + inorder(node.right); + }; + + inorder(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the recursion stack. + * $O(n)$ space for the output array. + +--- + +## 2. Iterative Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + stack = [] + cur = root + + while cur or stack: + while cur: + stack.append(cur) + cur = cur.left + cur = stack.pop() + res.append(cur.val) + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + + while (cur != null || !stack.isEmpty()) { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + cur = stack.pop(); + res.add(cur.val); + cur = cur.right; + } + + return res; + } +} +``` + +```cpp +/** + * 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 inorderTraversal(TreeNode* root) { + vector res; + stack stack; + TreeNode* cur = root; + + while (cur || !stack.empty()) { + while (cur) { + stack.push(cur); + cur = cur->left; + } + cur = stack.top(); + stack.pop(); + res.push_back(cur->val); + cur = cur->right; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + inorderTraversal(root) { + const res = []; + const stack = []; + let cur = root; + + while (cur || stack.length > 0) { + while (cur) { + stack.push(cur); + cur = cur.left; + } + cur = stack.pop(); + res.push(cur.val); + cur = cur.right; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the stack. + * $O(n)$ space for the output array. + +--- + +## 3. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + cur = root + + while cur: + if not cur.left: + res.append(cur.val) + cur = cur.right + else: + prev = cur.left + while prev.right and prev.right != cur: + prev = prev.right + + if not prev.right: + prev.right = cur + cur = cur.left + else: + prev.right = None + res.append(cur.val) + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + res.add(cur.val); + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + res.add(cur.val); + cur = cur.right; + } + } + } + + return res; + } +} +``` + +```cpp +/** + * 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 inorderTraversal(TreeNode* root) { + vector res; + TreeNode* cur = root; + + while (cur) { + if (!cur->left) { + res.push_back(cur->val); + cur = cur->right; + } else { + TreeNode* prev = cur->left; + while (prev->right && prev->right != cur) { + prev = prev->right; + } + + if (!prev->right) { + prev->right = cur; + cur = cur->left; + } else { + prev->right = nullptr; + res.push_back(cur->val); + cur = cur->right; + } + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + inorderTraversal(root) { + const res = []; + let cur = root; + + while (cur) { + if (!cur.left) { + res.push(cur.val); + cur = cur.right; + } else { + let prev = cur.left; + while (prev.right && prev.right !== cur) { + prev = prev.right; + } + + if (!prev.right) { + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + res.push(cur.val); + cur = cur.right; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. \ No newline at end of file diff --git a/articles/binary-tree-postorder-traversal.md b/articles/binary-tree-postorder-traversal.md new file mode 100644 index 000000000..554c3006a --- /dev/null +++ b/articles/binary-tree-postorder-traversal.md @@ -0,0 +1,662 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + + def postorder(node): + if not node: + return + + postorder(node.left) + postorder(node.right) + res.append(node.val) + + postorder(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private List res; + + public List postorderTraversal(TreeNode root) { + res = new ArrayList<>(); + postorder(root); + return res; + } + + private void postorder(TreeNode node) { + if (node == null) { + return; + } + postorder(node.left); + postorder(node.right); + res.add(node.val); + } +} +``` + +```cpp +/** + * 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 { + vector res; + +public: + vector postorderTraversal(TreeNode* root) { + postorder(root); + return res; + } + +private: + void postorder(TreeNode* node) { + if (!node) { + return; + } + postorder(node->left); + postorder(node->right); + res.push_back(node->val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + postorderTraversal(root) { + const res = []; + + const postorder = (node) => { + if (!node) return; + postorder(node.left); + postorder(node.right); + res.push(node.val); + }; + + postorder(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the recursion stack. + * $O(n)$ space for the output array. + +--- + +## 2. Iterative Depth First Search - I + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + stack = [root] + visit = [False] + res = [] + + while stack: + cur, v = stack.pop(), visit.pop() + if cur: + if v: + res.append(cur.val) + else: + stack.append(cur) + visit.append(True) + stack.append(cur.right) + visit.append(False) + stack.append(cur.left) + visit.append(False) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List postorderTraversal(TreeNode root) { + Stack stack = new Stack<>(); + Stack visit = new Stack<>(); + List res = new ArrayList<>(); + + stack.push(root); + visit.push(false); + + while (!stack.isEmpty()) { + TreeNode cur = stack.pop(); + boolean v = visit.pop(); + + if (cur != null) { + if (v) { + res.add(cur.val); + } else { + stack.push(cur); + visit.push(true); + stack.push(cur.right); + visit.push(false); + stack.push(cur.left); + visit.push(false); + } + } + } + + return res; + } +} +``` + +```cpp +/** + * 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 postorderTraversal(TreeNode* root) { + stack stk; + stack visit; + vector res; + + stk.push(root); + visit.push(false); + + while (!stk.empty()) { + TreeNode* cur = stk.top(); + bool v = visit.top(); + stk.pop(); + visit.pop(); + + if (cur) { + if (v) { + res.push_back(cur->val); + } else { + stk.push(cur); + visit.push(true); + stk.push(cur->right); + visit.push(false); + stk.push(cur->left); + visit.push(false); + } + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + postorderTraversal(root) { + const stack = [root]; + const visit = [false]; + const res = []; + + while (stack.length) { + const cur = stack.pop(); + const v = visit.pop(); + + if (cur) { + if (v) { + res.push(cur.val); + } else { + stack.push(cur); + visit.push(true); + stack.push(cur.right); + visit.push(false); + stack.push(cur.left); + visit.push(false); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the stacks. + * $O(n)$ space for the output array. + +--- + +## 3. Iterative Depth First Search - II + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + stack = [] + cur = root + + while cur or stack: + if cur: + res.append(cur.val) + stack.append(cur) + cur = cur.right + else: + cur = stack.pop() + cur = cur.left + + res.reverse() + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + res.add(cur.val); + stack.push(cur); + cur = cur.right; + } else { + cur = stack.pop(); + cur = cur.left; + } + } + + Collections.reverse(res); + return res; + } +} +``` + +```cpp +/** + * 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 postorderTraversal(TreeNode* root) { + vector res; + stack stack; + TreeNode* cur = root; + + while (cur || !stack.empty()) { + if (cur) { + res.push_back(cur->val); + stack.push(cur); + cur = cur->right; + } else { + cur = stack.top(); + stack.pop(); + cur = cur->left; + } + } + + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + postorderTraversal(root) { + const res = []; + const stack = []; + let cur = root; + + while (cur || stack.length) { + if (cur) { + res.push(cur.val); + stack.push(cur); + cur = cur.right; + } else { + cur = stack.pop(); + cur = cur.left; + } + } + + res.reverse(); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the stack. + * $O(n)$ space for the output array. + +--- + +## 4. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + cur = root + + while cur: + if not cur.right: + res.append(cur.val) + cur = cur.left + else: + prev = cur.right + while prev.left and prev.left != cur: + prev = prev.left + + if not prev.left: + res.append(cur.val) + prev.left = cur + cur = cur.right + else: + prev.left = None + cur = cur.left + + res.reverse() + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + TreeNode cur = root; + + while (cur != null) { + if (cur.right == null) { + res.add(cur.val); + cur = cur.left; + } else { + TreeNode prev = cur.right; + while (prev.left != null && prev.left != cur) { + prev = prev.left; + } + + if (prev.left == null) { + res.add(cur.val); + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + cur = cur.left; + } + } + } + + Collections.reverse(res); + return res; + } +} +``` + +```cpp +/** + * 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 postorderTraversal(TreeNode* root) { + vector res; + TreeNode* cur = root; + + while (cur) { + if (!cur->right) { + res.push_back(cur->val); + cur = cur->left; + } else { + TreeNode* prev = cur->right; + while (prev->left && prev->left != cur) { + prev = prev->left; + } + + if (!prev->left) { + res.push_back(cur->val); + prev->left = cur; + cur = cur->right; + } else { + prev->left = nullptr; + cur = cur->left; + } + } + } + + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + postorderTraversal(root) { + const res = []; + let cur = root; + + while (cur) { + if (!cur.right) { + res.push(cur.val); + cur = cur.left; + } else { + let prev = cur.right; + while (prev.left && prev.left !== cur) { + prev = prev.left; + } + + if (!prev.left) { + res.push(cur.val); + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + cur = cur.left; + } + } + } + + res.reverse(); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. \ No newline at end of file diff --git a/articles/binary-tree-preorder-traversal.md b/articles/binary-tree-preorder-traversal.md new file mode 100644 index 000000000..fbcc8b4d6 --- /dev/null +++ b/articles/binary-tree-preorder-traversal.md @@ -0,0 +1,468 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + + def preorder(node): + if not node: + return + + res.append(node.val) + preorder(node.left) + preorder(node.right) + + preorder(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private List res; + + public List preorderTraversal(TreeNode root) { + res = new ArrayList<>(); + preorder(root); + return res; + } + + private void preorder(TreeNode node) { + if (node == null) { + return; + } + res.add(node.val); + preorder(node.left); + preorder(node.right); + } +} +``` + +```cpp +/** + * 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 { + vector res; + +public: + vector preorderTraversal(TreeNode* root) { + preorder(root); + return res; + } + +private: + void preorder(TreeNode* node) { + if (!node) { + return; + } + res.push_back(node->val); + preorder(node->left); + preorder(node->right); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + preorderTraversal(root) { + const res = []; + + const preorder = (node) => { + if (!node) return; + res.push(node.val); + preorder(node.left); + preorder(node.right); + }; + + preorder(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the recursion stack. + * $O(n)$ space for the output array. + +--- + +## 2. Iterative Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + stack = [] + cur = root + + while cur or stack: + if cur: + res.append(cur.val) + stack.append(cur.right) + cur = cur.left + else: + cur = stack.pop() + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + res.add(cur.val); + stack.push(cur.right); + cur = cur.left; + } else { + cur = stack.pop(); + } + } + + return res; + } +} +``` + +```cpp +/** + * 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 preorderTraversal(TreeNode* root) { + vector res; + stack stack; + TreeNode* cur = root; + + while (cur || !stack.empty()) { + if (cur) { + res.push_back(cur->val); + stack.push(cur->right); + cur = cur->left; + } else { + cur = stack.top(); + stack.pop(); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + preorderTraversal(root) { + const res = []; + const stack = []; + let cur = root; + + while (cur || stack.length > 0) { + if (cur) { + res.push(cur.val); + stack.push(cur.right); + cur = cur.left; + } else { + cur = stack.pop(); + + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(n)$ space for the stack. + * $O(n)$ space for the output array. + +--- + +## 3. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: + res = [] + cur = root + + while cur: + if not cur.left: + res.append(cur.val) + cur = cur.right + else: + prev = cur.left + while prev.right and prev.right != cur: + prev = prev.right + + if not prev.right: + res.append(cur.val) + prev.right = cur + cur = cur.left + else: + prev.right = None + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + res.add(cur.val); + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + res.add(cur.val); + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + cur = cur.right; + } + } + } + + return res; + } +} +``` + +```cpp +/** + * 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 preorderTraversal(TreeNode* root) { + vector res; + TreeNode* cur = root; + + while (cur) { + if (!cur->left) { + res.push_back(cur->val); + cur = cur->right; + } else { + TreeNode* prev = cur->left; + while (prev->right && prev->right != cur) { + prev = prev->right; + } + + if (!prev->right) { + res.push_back(cur->val); + prev->right = cur; + cur = cur->left; + } else { + prev->right = nullptr; + cur = cur->right; + } + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + preorderTraversal(root) { + const res = []; + let cur = root; + + while (cur) { + if (!cur.left) { + res.push(cur.val); + cur = cur.right; + } else { + let prev = cur.left; + while (prev.right && prev.right !== cur) { + prev = prev.right; + } + + if (!prev.right) { + res.push(cur.val); + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + cur = cur.right; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(n)$ space for the output array. \ No newline at end of file diff --git a/articles/construct-quad-tree.md b/articles/construct-quad-tree.md new file mode 100644 index 000000000..48e117a86 --- /dev/null +++ b/articles/construct-quad-tree.md @@ -0,0 +1,733 @@ +## 1. Recursion + +::tabs-start + +```python +""" +# Definition for a QuadTree node. +class Node: + def __init__(self, val, isLeaf, topLeft, topRight, bottomLeft, bottomRight): + self.val = val + self.isLeaf = isLeaf + self.topLeft = topLeft + self.topRight = topRight + self.bottomLeft = bottomLeft + self.bottomRight = bottomRight +""" + +class Solution: + def construct(self, grid: List[List[int]]) -> 'Node': + def dfs(n, r, c): + allSame = True + for i in range(n): + for j in range(n): + if grid[r][c] != grid[r + i][c + j]: + allSame = False + break + if allSame: + return Node(grid[r][c], True) + + n = n // 2 + topleft = dfs(n, r, c) + topright = dfs(n, r, c + n) + bottomleft = dfs(n, r + n, c) + bottomright = dfs(n, r + n, c + n) + + return Node(0, False, topleft, topright, bottomleft, bottomright) + + return dfs(len(grid), 0, 0) +``` + +```java +/* +// Definition for a QuadTree node. +class Node { + public boolean val; + public boolean isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + + public Node() { + this.val = false; + this.isLeaf = false; + this.topLeft = null; + this.topRight = null; + this.bottomLeft = null; + this.bottomRight = null; + } + + public Node(boolean val, boolean isLeaf) { + this.val = val; + this.isLeaf = isLeaf; + this.topLeft = null; + this.topRight = null; + this.bottomLeft = null; + this.bottomRight = null; + } + + public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) { + this.val = val; + this.isLeaf = isLeaf; + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomLeft = bottomLeft; + this.bottomRight = bottomRight; + } +} +*/ + +public class Solution { + public Node construct(int[][] grid) { + return dfs(grid, grid.length, 0, 0); + } + + private Node dfs(int[][] grid, int n, int r, int c) { + boolean allSame = true; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (grid[r][c] != grid[r + i][c + j]) { + allSame = false; + break; + } + } + } + + if (allSame) { + return new Node(grid[r][c] == 1, true); + } + + int mid = n / 2; + Node topLeft = dfs(grid, mid, r, c); + Node topRight = dfs(grid, mid, r, c + mid); + Node bottomLeft = dfs(grid, mid, r + mid, c); + Node bottomRight = dfs(grid, mid, r + mid, c + mid); + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + +```cpp +/* +// Definition for a QuadTree node. +class Node { +public: + bool val; + bool isLeaf; + Node* topLeft; + Node* topRight; + Node* bottomLeft; + Node* bottomRight; + + Node() { + val = false; + isLeaf = false; + topLeft = NULL; + topRight = NULL; + bottomLeft = NULL; + bottomRight = NULL; + } + + Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = NULL; + topRight = NULL; + bottomLeft = NULL; + bottomRight = NULL; + } + + Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +}; +*/ + +class Solution { +public: + Node* construct(vector>& grid) { + return dfs(grid, grid.size(), 0, 0); + } + +private: + Node* dfs(vector>& grid, int n, int r, int c) { + bool allSame = true; + + for (int i = 0; i < n && allSame; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[r][c] != grid[r + i][c + j]) { + allSame = false; + break; + } + } + } + + if (allSame) { + return new Node(grid[r][c] == 1, true); + } + + int mid = n / 2; + Node* topLeft = dfs(grid, mid, r, c); + Node* topRight = dfs(grid, mid, r, c + mid); + Node* bottomLeft = dfs(grid, mid, r + mid, c); + Node* bottomRight = dfs(grid, mid, r + mid, c + mid); + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +}; +``` + +```javascript +/** + * // Definition for a QuadTree node. + * class Node { + * constructor(val,isLeaf,topLeft,topRight,bottomLeft,bottomRight) { + * this.val = val; + * this.isLeaf = isLeaf; + * this.topLeft = topLeft; + * this.topRight = topRight; + * this.bottomLeft = bottomLeft; + * this.bottomRight = bottomRight; + * } + * } + */ + +class Solution { + /** + * @param {number[][]} grid + * @return {Node} + */ + construct(grid) { + const dfs = (n, r, c) => { + let allSame = true; + + for (let i = 0; i < n && allSame; i++) { + for (let j = 0; j < n; j++) { + if (grid[r][c] !== grid[r + i][c + j]) { + allSame = false; + break; + } + } + } + + if (allSame) { + return new Node(grid[r][c] === 1, true); + } + + const mid = Math.floor(n / 2); + const topLeft = dfs(mid, r, c); + const topRight = dfs(mid, r, c + mid); + const bottomLeft = dfs(mid, r + mid, c); + const bottomRight = dfs(mid, r + mid, c + mid); + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + }; + + return dfs(grid.length, 0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 \log n)$ +* Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 2. Recursion (Optimal) + +::tabs-start + +```python +""" +# Definition for a QuadTree node. +class Node: + def __init__(self, val, isLeaf, topLeft, topRight, bottomLeft, bottomRight): + self.val = val + self.isLeaf = isLeaf + self.topLeft = topLeft + self.topRight = topRight + self.bottomLeft = bottomLeft + self.bottomRight = bottomRight +""" + +class Solution: + def construct(self, grid: List[List[int]]) -> 'Node': + def dfs(n, r, c): + if n == 1: + return Node(grid[r][c] == 1, True) + + mid = n // 2 + topLeft = dfs(mid, r, c) + topRight = dfs(mid, r, c + mid) + bottomLeft = dfs(mid, r + mid, c) + bottomRight = dfs(mid, r + mid, c + mid) + + if (topLeft.isLeaf and topRight.isLeaf and + bottomLeft.isLeaf and bottomRight.isLeaf and + topLeft.val == topRight.val == bottomLeft.val == bottomRight.val): + return Node(topLeft.val, True) + + return Node(False, False, topLeft, topRight, bottomLeft, bottomRight) + + return dfs(len(grid), 0, 0) +``` + +```java +/* +// Definition for a QuadTree node. +class Node { + public boolean val; + public boolean isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + + public Node() { + this.val = false; + this.isLeaf = false; + this.topLeft = null; + this.topRight = null; + this.bottomLeft = null; + this.bottomRight = null; + } + + public Node(boolean val, boolean isLeaf) { + this.val = val; + this.isLeaf = isLeaf; + this.topLeft = null; + this.topRight = null; + this.bottomLeft = null; + this.bottomRight = null; + } + + public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) { + this.val = val; + this.isLeaf = isLeaf; + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomLeft = bottomLeft; + this.bottomRight = bottomRight; + } +} +*/ + +public class Solution { + public Node construct(int[][] grid) { + return dfs(grid, grid.length, 0, 0); + } + + private Node dfs(int[][] grid, int n, int r, int c) { + if (n == 1) { + return new Node(grid[r][c] == 1, true); + } + + int mid = n / 2; + Node topLeft = dfs(grid, mid, r, c); + Node topRight = dfs(grid, mid, r, c + mid); + Node bottomLeft = dfs(grid, mid, r + mid, c); + Node bottomRight = dfs(grid, mid, r + mid, c + mid); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val == topRight.val && + topLeft.val == bottomLeft.val && + topLeft.val == bottomRight.val) { + return new Node(topLeft.val, true); + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + +```cpp +/* +// Definition for a QuadTree node. +class Node { +public: + bool val; + bool isLeaf; + Node* topLeft; + Node* topRight; + Node* bottomLeft; + Node* bottomRight; + + Node() { + val = false; + isLeaf = false; + topLeft = NULL; + topRight = NULL; + bottomLeft = NULL; + bottomRight = NULL; + } + + Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = NULL; + topRight = NULL; + bottomLeft = NULL; + bottomRight = NULL; + } + + Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +}; +*/ + +class Solution { +public: + Node* construct(vector>& grid) { + return dfs(grid, grid.size(), 0, 0); + } + +private: + Node* dfs(vector>& grid, int n, int r, int c) { + if (n == 1) { + return new Node(grid[r][c] == 1, true); + } + + int mid = n / 2; + Node* topLeft = dfs(grid, mid, r, c); + Node* topRight = dfs(grid, mid, r, c + mid); + Node* bottomLeft = dfs(grid, mid, r + mid, c); + Node* bottomRight = dfs(grid, mid, r + mid, c + mid); + + if (topLeft->isLeaf && topRight->isLeaf && + bottomLeft->isLeaf && bottomRight->isLeaf && + topLeft->val == topRight->val && + topLeft->val == bottomLeft->val && + topLeft->val == bottomRight->val) { + return new Node(topLeft->val, true); + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +}; +``` + +```javascript +/** + * // Definition for a QuadTree node. + * class Node { + * constructor(val,isLeaf,topLeft,topRight,bottomLeft,bottomRight) { + * this.val = val; + * this.isLeaf = isLeaf; + * this.topLeft = topLeft; + * this.topRight = topRight; + * this.bottomLeft = bottomLeft; + * this.bottomRight = bottomRight; + * } + * } + */ + +class Solution { + /** + * @param {number[][]} grid + * @return {Node} + */ + construct(grid) { + const dfs = (n, r, c) => { + if (n === 1) { + return new Node(grid[r][c] === 1, true); + } + + const mid = Math.floor(n / 2); + const topLeft = dfs(mid, r, c); + const topRight = dfs(mid, r, c + mid); + const bottomLeft = dfs(mid, r + mid, c); + const bottomRight = dfs(mid, r + mid, c + mid); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val === topRight.val && + topLeft.val === bottomLeft.val && + topLeft.val === bottomRight.val) { + return new Node(topLeft.val, true); + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + }; + + return dfs(grid.length, 0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 3. Recursion (Space Optimized) + +::tabs-start + +```python +""" +# Definition for a QuadTree node. +class Node: + def __init__(self, val, isLeaf, topLeft, topRight, bottomLeft, bottomRight): + self.val = val + self.isLeaf = isLeaf + self.topLeft = topLeft + self.topRight = topRight + self.bottomLeft = bottomLeft + self.bottomRight = bottomRight +""" + +class Solution: + def construct(self, grid: List[List[int]]) -> 'Node': + leafNodes = { + 0: Node(False, True), + 1: Node(True, True) + } + + def dfs(n, r, c): + if n == 1: + return leafNodes[grid[r][c]] + + n //= 2 + topLeft = dfs(n, r, c) + topRight = dfs(n, r, c + n) + bottomLeft = dfs(n, r + n, c) + bottomRight = dfs(n, r + n, c + n) + + if (topLeft.isLeaf and topRight.isLeaf and + bottomLeft.isLeaf and bottomRight.isLeaf and + topLeft.val == topRight.val == bottomLeft.val == bottomRight.val): + return topLeft + + return Node(False, False, topLeft, topRight, bottomLeft, bottomRight) + + return dfs(len(grid), 0, 0) +``` + +```java +/* +// Definition for a QuadTree node. +class Node { + public boolean val; + public boolean isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + + public Node() { + this.val = false; + this.isLeaf = false; + this.topLeft = null; + this.topRight = null; + this.bottomLeft = null; + this.bottomRight = null; + } + + public Node(boolean val, boolean isLeaf) { + this.val = val; + this.isLeaf = isLeaf; + this.topLeft = null; + this.topRight = null; + this.bottomLeft = null; + this.bottomRight = null; + } + + public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) { + this.val = val; + this.isLeaf = isLeaf; + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomLeft = bottomLeft; + this.bottomRight = bottomRight; + } +} +*/ + +public class Solution { + private static final Node falseLeaf = new Node(false, true); + private static final Node trueLeaf = new Node(true, true); + + public Node construct(int[][] grid) { + return dfs(grid, grid.length, 0, 0); + } + + private Node dfs(int[][] grid, int n, int r, int c) { + if (n == 1) { + return grid[r][c] == 1 ? trueLeaf : falseLeaf; + } + + n /= 2; + Node topLeft = dfs(grid, n, r, c); + Node topRight = dfs(grid, n, r, c + n); + Node bottomLeft = dfs(grid, n, r + n, c); + Node bottomRight = dfs(grid, n, r + n, c + n); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val == topRight.val && topLeft.val == bottomLeft.val && + topLeft.val == bottomRight.val) { + return topLeft; + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + +```cpp +/* +// Definition for a QuadTree node. +class Node { +public: + bool val; + bool isLeaf; + Node* topLeft; + Node* topRight; + Node* bottomLeft; + Node* bottomRight; + + Node() { + val = false; + isLeaf = false; + topLeft = NULL; + topRight = NULL; + bottomLeft = NULL; + bottomRight = NULL; + } + + Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = NULL; + topRight = NULL; + bottomLeft = NULL; + bottomRight = NULL; + } + + Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +}; +*/ + +class Solution { +private: + Node* falseLeaf = new Node(false, true); + Node* trueLeaf = new Node(true, true); + +public: + Node* construct(vector>& grid) { + return dfs(grid, grid.size(), 0, 0); + } + +private: + Node* dfs(vector>& grid, int n, int r, int c) { + if (n == 1) { + return grid[r][c] == 1 ? trueLeaf : falseLeaf; + } + + n /= 2; + Node* topLeft = dfs(grid, n, r, c); + Node* topRight = dfs(grid, n, r, c + n); + Node* bottomLeft = dfs(grid, n, r + n, c); + Node* bottomRight = dfs(grid, n, r + n, c + n); + + if (topLeft->isLeaf && topRight->isLeaf && + bottomLeft->isLeaf && bottomRight->isLeaf && + topLeft->val == topRight->val && topLeft->val == bottomLeft->val && + topLeft->val == bottomRight->val) { + return topLeft; + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +}; +``` + +```javascript +/** + * // Definition for a QuadTree node. + * class Node { + * constructor(val,isLeaf,topLeft,topRight,bottomLeft,bottomRight) { + * this.val = val; + * this.isLeaf = isLeaf; + * this.topLeft = topLeft; + * this.topRight = topRight; + * this.bottomLeft = bottomLeft; + * this.bottomRight = bottomRight; + * } + * } + */ + +class Solution { + /** + * @param {number[][]} grid + * @return {Node} + */ + construct(grid) { + const falseLeaf = new Node(false, true); + const trueLeaf = new Node(true, true); + + const dfs = (n, r, c) => { + if (n === 1) { + return grid[r][c] === 1 ? trueLeaf : falseLeaf; + } + + n = Math.floor(n / 2); + const topLeft = dfs(n, r, c); + const topRight = dfs(n, r, c + n); + const bottomLeft = dfs(n, r + n, c); + const bottomRight = dfs(n, r + n, c + n); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val === topRight.val && topLeft.val === bottomLeft.val && + topLeft.val === bottomRight.val) { + return topLeft; + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + }; + + return dfs(grid.length, 0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(\log n)$ for recursion stack. \ No newline at end of file diff --git a/articles/delete-leaves-with-a-given-value.md b/articles/delete-leaves-with-a-given-value.md new file mode 100644 index 000000000..ccfb4637b --- /dev/null +++ b/articles/delete-leaves-with-a-given-value.md @@ -0,0 +1,577 @@ +## 1. Recursion (Postorder Traversal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def removeLeafNodes(self, root: Optional[TreeNode], target: int) -> Optional[TreeNode]: + if not root: + return None + + root.left = self.removeLeafNodes(root.left, target) + root.right = self.removeLeafNodes(root.right, target) + + if not root.left and not root.right and root.val == target: + return None + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode removeLeafNodes(TreeNode root, int target) { + if (root == null) { + return null; + } + + root.left = removeLeafNodes(root.left, target); + root.right = removeLeafNodes(root.right, target); + + if (root.left == null && root.right == null && root.val == target) { + return null; + } + + return root; + } +} +``` + +```cpp +/** + * 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* removeLeafNodes(TreeNode* root, int target) { + if (!root) { + return nullptr; + } + + root->left = removeLeafNodes(root->left, target); + root->right = removeLeafNodes(root->right, target); + + if (!root->left && !root->right && root->val == target) { + return nullptr; + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} target + * @return {TreeNode} + */ + removeLeafNodes(root, target) { + if (!root) { + return null; + } + + root.left = this.removeLeafNodes(root.left, target); + root.right = this.removeLeafNodes(root.right, target); + + if (!root.left && !root.right && root.val === target) { + return null; + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Iterative Postorder Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def removeLeafNodes(self, root: Optional[TreeNode], target: int) -> Optional[TreeNode]: + stack = [root] + visit = set() + parents = {root: None} + + while stack: + node = stack.pop() + if not node.left and not node.right: + if node.val == target: + p = parents[node] + if not p: + return None + if p.left == node: + p.left = None + if p.right == node: + p.right = None + elif node not in visit: + visit.add(node) + stack.append(node) + if node.left: + stack.append(node.left) + parents[node.left] = node + if node.right: + stack.append(node.right) + parents[node.right] = node + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode removeLeafNodes(TreeNode root, int target) { + Stack stack = new Stack<>(); + Set visit = new HashSet<>(); + Map parents = new HashMap<>(); + parents.put(root, null); + stack.push(root); + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + if (node.left == null && node.right == null) { + if (node.val == target) { + TreeNode p = parents.get(node); + if (p == null) { + return null; + } + if (p.left == node) { + p.left = null; + } + if (p.right == node) { + p.right = null; + } + } + } else if (!visit.contains(node)) { + visit.add(node); + stack.push(node); + if (node.left != null) { + stack.push(node.left); + parents.put(node.left, node); + } + if (node.right != null) { + stack.push(node.right); + parents.put(node.right, node); + } + } + } + + return root; + } +} +``` + +```cpp +/** + * 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* removeLeafNodes(TreeNode* root, int target) { + stack stack; + unordered_set visit; + unordered_map parents; + parents[root] = nullptr; + stack.push(root); + + while (!stack.empty()) { + TreeNode* node = stack.top(); + stack.pop(); + if (!node->left && !node->right) { + if (node->val == target) { + TreeNode* p = parents[node]; + if (!p) { + return nullptr; + } + if (p->left == node) { + p->left = nullptr; + } + if (p->right == node) { + p->right = nullptr; + } + } + } else if (visit.find(node) == visit.end()) { + visit.insert(node); + stack.push(node); + if (node->left) { + stack.push(node->left); + parents[node->left] = node; + } + if (node->right) { + stack.push(node->right); + parents[node->right] = node; + } + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} target + * @return {TreeNode} + */ + removeLeafNodes(root, target) { + const stack = [root]; + const visit = new Set(); + const parents = new Map(); + parents.set(root, null); + + while (stack.length > 0) { + const node = stack.pop(); + if (!node.left && !node.right) { + if (node.val === target) { + const p = parents.get(node); + if (!p) { + return null; + } + if (p.left === node) { + p.left = null; + } + if (p.right === node) { + p.right = null; + } + } + } else if (!visit.has(node)) { + visit.add(node); + stack.push(node); + if (node.left) { + stack.push(node.left); + parents.set(node.left, node); + } + if (node.right) { + stack.push(node.right); + parents.set(node.right, node); + } + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Iterative Postorder Traversal (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def removeLeafNodes(self, root: Optional[TreeNode], target: int) -> Optional[TreeNode]: + if not root: + return None + + stack = [] + cur = root + visited = None + + while stack or cur: + while cur: + stack.append(cur) + cur = cur.left + + cur = stack[-1] + if cur.right and cur.right != visited: + cur = cur.right + continue + + stack.pop() + if not cur.left and not cur.right and cur.val == target: + if not stack: + return None + + parent = stack[-1] + if parent.left == cur: + parent.left = None + elif parent.right == cur: + parent.right = None + else: + visited = cur + + cur = None + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode removeLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + Stack stack = new Stack<>(); + TreeNode cur = root, visited = null; + + while (!stack.isEmpty() || cur != null) { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + + cur = stack.peek(); + if (cur.right != null && cur.right != visited) { + cur = cur.right; + continue; + } + + stack.pop(); + if (cur.left == null && cur.right == null && cur.val == target) { + if (stack.isEmpty()) return null; + + TreeNode parent = stack.peek(); + if (parent.left == cur) { + parent.left = null; + } else if (parent.right == cur) { + parent.right = null; + } + } else { + visited = cur; + } + + cur = null; + } + + return root; + } +} +``` + +```cpp +/** + * 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* removeLeafNodes(TreeNode* root, int target) { + if (!root) return nullptr; + + stack stack; + TreeNode* cur = root; + TreeNode* visited = nullptr; + + while (!stack.empty() || cur) { + while (cur) { + stack.push(cur); + cur = cur->left; + } + + cur = stack.top(); + if (cur->right && cur->right != visited) { + cur = cur->right; + continue; + } + + stack.pop(); + if (!cur->left && !cur->right && cur->val == target) { + if (stack.empty()) return nullptr; + + TreeNode* parent = stack.top(); + if (parent->left == cur) { + parent->left = nullptr; + } else if (parent->right == cur) { + parent->right = nullptr; + } + } else { + visited = cur; + } + + cur = nullptr; + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} target + * @return {TreeNode} + */ + removeLeafNodes(root, target) { + if (!root) return null; + + const stack = []; + let cur = root, visited = null; + + while (stack.length > 0 || cur !== null) { + while (cur !== null) { + stack.push(cur); + cur = cur.left; + } + + cur = stack[stack.length - 1]; + if (cur.right && cur.right !== visited) { + cur = cur.right; + continue; + } + + stack.pop(); + if (!cur.left && !cur.right && cur.val === target) { + if (stack.length === 0) return null; + + const parent = stack[stack.length - 1]; + if (parent.left === cur) { + parent.left = null; + } else if (parent.right === cur) { + parent.right = null; + } + } else { + visited = cur; + } + + cur = null; + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/delete-node-in-a-bst.md b/articles/delete-node-in-a-bst.md new file mode 100644 index 000000000..4b086145a --- /dev/null +++ b/articles/delete-node-in-a-bst.md @@ -0,0 +1,632 @@ +## 1. Recursion - I + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]: + if not root: + return root + + if key > root.val: + root.right = self.deleteNode(root.right, key) + elif key < root.val: + root.left = self.deleteNode(root.left, key) + else: + if not root.left: + return root.right + elif not root.right: + return root.left + + cur = root.right + while cur.left: + cur = cur.left + root.val = cur.val + root.right = self.deleteNode(root.right, root.val) + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode deleteNode(TreeNode root, int key) { + if (root == null) return root; + + if (key > root.val) { + root.right = deleteNode(root.right, key); + } else if (key < root.val) { + root.left = deleteNode(root.left, key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + root.val = cur.val; + root.right = deleteNode(root.right, root.val); + } + + return root; + } +} +``` + +```cpp +/** + * 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* deleteNode(TreeNode* root, int key) { + if (!root) return root; + + if (key > root->val) { + root->right = deleteNode(root->right, key); + } else if (key < root->val) { + root->left = deleteNode(root->left, key); + } else { + if (!root->left) return root->right; + if (!root->right) return root->left; + + TreeNode* cur = root->right; + while (cur->left) { + cur = cur->left; + } + root->val = cur->val; + root->right = deleteNode(root->right, root->val); + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} key + * @return {TreeNode} + */ + deleteNode(root, key) { + if (!root) return root; + + if (key > root.val) { + root.right = this.deleteNode(root.right, key); + } else if (key < root.val) { + root.left = this.deleteNode(root.left, key); + } else { + if (!root.left) return root.right; + if (!root.right) return root.left; + + let cur = root.right; + while (cur.left) { + cur = cur.left; + } + root.val = cur.val; + root.right = this.deleteNode(root.right, root.val); + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(h)$ +* Space complexity: $O(h)$ for the recursion stack. + +> Where $h$ is the height of the given binary search tree. + +--- + +## 2. Recursion - II + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]: + if not root: + return root + + if key > root.val: + root.right = self.deleteNode(root.right, key) + elif key < root.val: + root.left = self.deleteNode(root.left, key) + else: + if not root.left: + return root.right + elif not root.right: + return root.left + + cur = root.right + while cur.left: + cur = cur.left + cur.left = root.left + res = root.right + del root + return res + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode deleteNode(TreeNode root, int key) { + if (root == null) return root; + + if (key > root.val) { + root.right = deleteNode(root.right, key); + } else if (key < root.val) { + root.left = deleteNode(root.left, key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + cur.left = root.left; + TreeNode res = root.right; + root = null; + return res; + } + + return root; + } +} +``` + +```cpp +/** + * 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* deleteNode(TreeNode* root, int key) { + if (!root) return root; + + if (key > root->val) { + root->right = deleteNode(root->right, key); + } else if (key < root->val) { + root->left = deleteNode(root->left, key); + } else { + if (!root->left) return root->right; + if (!root->right) return root->left; + + TreeNode* cur = root->right; + while (cur->left) { + cur = cur->left; + } + cur->left = root->left; + TreeNode* res = root->right; + delete root; + return res; + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} key + * @return {TreeNode} + */ + deleteNode(root, key) { + if (!root) return root; + + if (key > root.val) { + root.right = this.deleteNode(root.right, key); + } else if (key < root.val) { + root.left = this.deleteNode(root.left, key); + } else { + if (!root.left) return root.right; + if (!root.right) return root.left; + + let cur = root.right; + while (cur.left) { + cur = cur.left; + } + cur.left = root.left; + let res = root.right; + root = null; + return res; + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(h)$ +* Space complexity: $O(h)$ for the recursion stack. + +> Where $h$ is the height of the given binary search tree. + +--- + +## 3. Iteration + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]: + if not root: + return root + + parent = None + cur = root + + # Find the node to delete + while cur and cur.val != key: + parent = cur + if key > cur.val: + cur = cur.right + else: + cur = cur.left + + if not cur: + return root + + # Node with only one child or no child + if not cur.left or not cur.right: + child = cur.left if cur.left else cur.right + if not parent: + return child + if parent.left == cur: + parent.left = child + else: + parent.right = child + else: + # Node with two children + par = None # parent of right subTree min node + delNode = cur + cur = cur.right + while cur.left: + par = cur + cur = cur.left + + if par: # if there was a left traversal + par.left = cur.right + cur.right = delNode.right + + cur.left = delNode.left + + if not parent: # if we're deleting root + return cur + + if parent.left == delNode: + parent.left = cur + else: + parent.right = cur + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode deleteNode(TreeNode root, int key) { + if (root == null) return root; + + TreeNode parent = null; + TreeNode cur = root; + + // Find the node to delete + while (cur != null && cur.val != key) { + parent = cur; + if (key > cur.val) { + cur = cur.right; + } else { + cur = cur.left; + } + } + + if (cur == null) return root; + + // Node with only one child or no child + if (cur.left == null || cur.right == null) { + TreeNode child = (cur.left != null) ? cur.left : cur.right; + if (parent == null) return child; + if (parent.left == cur) { + parent.left = child; + } else { + parent.right = child; + } + } else { + // Node with two children + TreeNode par = null; // parent of right subtree's min node + TreeNode delNode = cur; + cur = cur.right; + while (cur.left != null) { + par = cur; + cur = cur.left; + } + + if (par != null) { // if there was a left traversal + par.left = cur.right; + cur.right = delNode.right; + } + cur.left = delNode.left; + + if (parent == null) return cur; // if deleting root + + if (parent.left == delNode) { + parent.left = cur; + } else { + parent.right = cur; + } + } + + return root; + } +} +``` + +```cpp +/** + * 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* deleteNode(TreeNode* root, int key) { + if (!root) return root; + + TreeNode* parent = nullptr; + TreeNode* cur = root; + + // Find the node to delete + while (cur && cur->val != key) { + parent = cur; + if (key > cur->val) { + cur = cur->right; + } else { + cur = cur->left; + } + } + + if (!cur) return root; + + // Node with only one child or no child + if (!cur->left || !cur->right) { + TreeNode* child = cur->left ? cur->left : cur->right; + if (!parent) return child; + if (parent->left == cur) { + parent->left = child; + } else { + parent->right = child; + } + } else { + // Node with two children + TreeNode* par = nullptr; // parent of right subtree's min node + TreeNode* delNode = cur; + cur = cur->right; + while (cur->left) { + par = cur; + cur = cur->left; + } + + if (par) { // if there was a left traversal + par->left = cur->right; + cur->right = delNode->right; + } + cur->left = delNode->left; + + if (!parent) return cur; // if deleting root + + if (parent->left == delNode) { + parent->left = cur; + } else { + parent->right = cur; + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} key + * @return {TreeNode} + */ + deleteNode(root, key) { + if (!root) return root; + + let parent = null; + let cur = root; + + // Find the node to delete + while (cur && cur.val !== key) { + parent = cur; + if (key > cur.val) { + cur = cur.right; + } else { + cur = cur.left; + } + } + + if (!cur) return root; + + // Node with only one child or no child + if (!cur.left || !cur.right) { + const child = cur.left || cur.right; + if (!parent) return child; + if (parent.left === cur) { + parent.left = child; + } else { + parent.right = child; + } + } else { + // Node with two children + let par = null; // parent of right subtree's min node + const delNode = cur; + cur = cur.right; + while (cur.left) { + par = cur; + cur = cur.left; + } + + if (par) { // if there was a left traversal + par.left = cur.right; + cur.right = delNode.right; + } + cur.left = delNode.left; + + if (!parent) return cur; // if deleting root + + if (parent.left === delNode) { + parent.left = cur; + } else { + parent.right = cur; + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(h)$ +* Space complexity: $O(1)$ extra space. + +> Where $h$ is the height of the given binary search tree. \ No newline at end of file diff --git a/articles/house-robber-iii.md b/articles/house-robber-iii.md new file mode 100644 index 000000000..08d521c95 --- /dev/null +++ b/articles/house-robber-iii.md @@ -0,0 +1,457 @@ +## 1. Recursion + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def rob(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + + res = root.val + if root.left: + res += self.rob(root.left.left) + self.rob(root.left.right) + if root.right: + res += self.rob(root.right.left) + self.rob(root.right.right) + + res = max(res, self.rob(root.left) + self.rob(root.right)) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int rob(TreeNode root) { + if (root == null) { + return 0; + } + + int res = root.val; + if (root.left != null) { + res += rob(root.left.left) + rob(root.left.right); + } + if (root.right != null) { + res += rob(root.right.left) + rob(root.right.right); + } + + res = Math.max(res, rob(root.left) + rob(root.right)); + return res; + } +} +``` + +```cpp +/** + * 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 rob(TreeNode* root) { + if (!root) { + return 0; + } + + int res = root->val; + if (root->left) { + res += rob(root->left->left) + rob(root->left->right); + } + if (root->right) { + res += rob(root->right->left) + rob(root->right->right); + } + + res = max(res, rob(root->left) + rob(root->right)); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + rob(root) { + if (!root) { + return 0; + } + + let res = root.val; + if (root.left) { + res += this.rob(root.left.left) + this.rob(root.left.right); + } + if (root.right) { + res += this.rob(root.right.left) + this.rob(root.right.right); + } + + res = Math.max(res, this.rob(root.left) + this.rob(root.right)); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Memoization) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def rob(self, root: Optional[TreeNode]) -> int: + cache = { None : 0 } + + def dfs(root): + if root in cache: + return cache[root] + + cache[root] = root.val + if root.left: + cache[root] += dfs(root.left.left) + dfs(root.left.right) + if root.right: + cache[root] += dfs(root.right.left) + dfs(root.right.right) + + cache[root] = max(cache[root], dfs(root.left) + dfs(root.right)) + return cache[root] + + return dfs(root) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map cache; + + public int rob(TreeNode root) { + cache = new HashMap<>(); + cache.put(null, 0); + return dfs(root); + } + + private int dfs(TreeNode root) { + if (cache.containsKey(root)) { + return cache.get(root); + } + + int res = root.val; + if (root.left != null) { + res += dfs(root.left.left) + dfs(root.left.right); + } + if (root.right != null) { + res += dfs(root.right.left) + dfs(root.right.right); + } + + res = Math.max(res, dfs(root.left) + dfs(root.right)); + cache.put(root, res); + return res; + } +} +``` + +```cpp +/** + * 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 { + unordered_map cache; + +public: + int rob(TreeNode* root) { + cache[nullptr] = 0; + return dfs(root); + } + +private: + int dfs(TreeNode* root) { + if (cache.find(root) != cache.end()) { + return cache[root]; + } + + int res = root->val; + if (root->left) { + res += rob(root->left->left) + rob(root->left->right); + } + if (root->right) { + res += rob(root->right->left) + rob(root->right->right); + } + + res = max(res, rob(root->left) + rob(root->right)); + cache[root] = res; + return res; + + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + rob(root) { + const cache = new Map(); + cache.set(null, 0); + + const dfs = (root) => { + if (cache.has(root)) { + return cache.get(root); + } + + let res = root.val; + if (root.left) { + res += dfs(root.left.left) + dfs(root.left.right); + } + if (root.right) { + res += dfs(root.right.left) + dfs(root.right.right); + } + + res = Math.max(res, dfs(root.left) + dfs(root.right)); + cache.set(root, res); + return res; + }; + + return dfs(root); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def rob(self, root: TreeNode) -> int: + def dfs(root): + if not root: + return [0, 0] + + leftPair = dfs(root.left) + rightPair = dfs(root.right) + + withRoot = root.val + leftPair[1] + rightPair[1] + withoutRoot = max(leftPair) + max(rightPair) + + return [withRoot, withoutRoot] + + return max(dfs(root)) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int rob(TreeNode root) { + int[] result = dfs(root); + return Math.max(result[0], result[1]); + } + + private int[] dfs(TreeNode root) { + if (root == null) { + return new int[]{0, 0}; + } + + int[] leftPair = dfs(root.left); + int[] rightPair = dfs(root.right); + + int withRoot = root.val + leftPair[1] + rightPair[1]; + int withoutRoot = Math.max(leftPair[0], leftPair[1]) + + Math.max(rightPair[0], rightPair[1]); + + return new int[]{withRoot, withoutRoot}; + } +} +``` + +```cpp +/** + * 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 rob(TreeNode* root) { + auto result = dfs(root); + return max(result.first, result.second); + } + +private: + pair dfs(TreeNode* root) { + if (!root) { + return {0, 0}; + } + + auto leftPair = dfs(root->left); + auto rightPair = dfs(root->right); + + int withRoot = root->val + leftPair.second + rightPair.second; + int withoutRoot = max(leftPair.first, leftPair.second) + + max(rightPair.first, rightPair.second); + + return {withRoot, withoutRoot}; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + rob(root) { + const dfs = (node) => { + if (!node) { + return [0, 0]; + } + + const leftPair = dfs(node.left); + const rightPair = dfs(node.right); + + const withRoot = node.val + leftPair[1] + rightPair[1]; + const withoutRoot = Math.max(...leftPair) + Math.max(...rightPair); + + return [withRoot, withoutRoot]; + }; + + const result = dfs(root); + return Math.max(...result); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. \ No newline at end of file diff --git a/articles/insert-into-a-binary-search-tree.md b/articles/insert-into-a-binary-search-tree.md new file mode 100644 index 000000000..d8597610b --- /dev/null +++ b/articles/insert-into-a-binary-search-tree.md @@ -0,0 +1,292 @@ +## 1. Recursion + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: + if not root: + return TreeNode(val) + + if val > root.val: + root.right = self.insertIntoBST(root.right, val) + else: + root.left = self.insertIntoBST(root.left, val) + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode insertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + + if (val > root.val) { + root.right = insertIntoBST(root.right, val); + } else { + root.left = insertIntoBST(root.left, val); + } + + return root; + } +} +``` + +```cpp +/** + * 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* insertIntoBST(TreeNode* root, int val) { + if (!root) { + return new TreeNode(val); + } + + if (val > root->val) { + root->right = insertIntoBST(root->right, val); + } else { + root->left = insertIntoBST(root->left, val); + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} val + * @return {TreeNode} + */ + insertIntoBST(root, val) { + if (!root) { + return new TreeNode(val); + } + + if (val > root.val) { + root.right = this.insertIntoBST(root.right, val); + } else { + root.left = this.insertIntoBST(root.left, val); + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(h)$ +* Space complexity: $O(h)$ for the recursion stack. + +> Where $h$ is the height of the given binary search tree. + +--- + +## 2. Iteration + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: + if not root: + return TreeNode(val) + + cur = root + while True: + if val > cur.val: + if not cur.right: + cur.right = TreeNode(val) + return root + cur = cur.right + else: + if not cur.left: + cur.left = TreeNode(val) + return root + cur = cur.left +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode insertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + + TreeNode cur = root; + while (true) { + if (val > cur.val) { + if (cur.right == null) { + cur.right = new TreeNode(val); + return root; + } + cur = cur.right; + } else { + if (cur.left == null) { + cur.left = new TreeNode(val); + return root; + } + cur = cur.left; + } + } + } +} +``` + +```cpp +/** + * 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* insertIntoBST(TreeNode* root, int val) { + if (!root) { + return new TreeNode(val); + } + + TreeNode* cur = root; + while (true) { + if (val > cur->val) { + if (!cur->right) { + cur->right = new TreeNode(val); + return root; + } + cur = cur->right; + } else { + if (!cur->left) { + cur->left = new TreeNode(val); + return root; + } + cur = cur->left; + } + } + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} val + * @return {TreeNode} + */ + insertIntoBST(root, val) { + if (!root) { + return new TreeNode(val); + } + + let cur = root; + while (true) { + if (val > cur.val) { + if (!cur.right) { + cur.right = new TreeNode(val); + return root; + } + cur = cur.right; + } else { + if (!cur.left) { + cur.left = new TreeNode(val); + return root; + } + cur = cur.left; + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(h)$ +* Space complexity: $O(1)$ extra space. + +> Where $h$ is the height of the given binary search tree. \ No newline at end of file diff --git a/articles/word-break-ii.md b/articles/word-break-ii.md new file mode 100644 index 000000000..c075d2b67 --- /dev/null +++ b/articles/word-break-ii.md @@ -0,0 +1,975 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> List[str]: + wordDict = set(wordDict) + + def backtrack(i): + if i == len(s): + res.append(" ".join(cur)) + return + + for j in range(i, len(s)): + w = s[i:j + 1] + if w in wordDict: + cur.append(w) + backtrack(j + 1) + cur.pop() + + cur = [] + res = [] + backtrack(0) + return res +``` + +```java +public class Solution { + private Set wordSet; + private List res; + + public List wordBreak(String s, List wordDict) { + wordSet = new HashSet<>(wordDict); + res = new ArrayList<>(); + List cur = new ArrayList<>(); + backtrack(s, 0, cur); + return res; + } + + private void backtrack(String s, int i, List cur) { + if (i == s.length()) { + res.add(String.join(" ", cur)); + return; + } + + for (int j = i; j < s.length(); j++) { + String w = s.substring(i, j + 1); + if (wordSet.contains(w)) { + cur.add(w); + backtrack(s, j + 1, cur); + cur.remove(cur.size() - 1); + } + } + } +} +``` + +```cpp +class Solution { + unordered_set wordSet; + vector res; + +public: + vector wordBreak(string s, vector& wordDict) { + wordSet = unordered_set(wordDict.begin(), wordDict.end()); + vector cur; + backtrack(s, 0, cur); + return res; + } + +private: + void backtrack(const string& s, int i, vector& cur) { + if (i == s.size()) { + res.push_back(join(cur)); + return; + } + + for (int j = i; j < s.size(); ++j) { + string w = s.substr(i, j - i + 1); + if (wordSet.count(w)) { + cur.push_back(w); + backtrack(s, j + 1, cur); + cur.pop_back(); + } + } + } + + string join(const vector& words) { + ostringstream oss; + for (int i = 0; i < words.size(); ++i) { + if (i > 0) oss << " "; + oss << words[i]; + } + return oss.str(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ + wordBreak(s, wordDict) { + const wordSet = new Set(wordDict); + const res = []; + const cur = []; + + const backtrack = (i) => { + if (i === s.length) { + res.push(cur.join(" ")); + return; + } + + for (let j = i; j < s.length; j++) { + const w = s.substring(i, j + 1); + if (wordSet.has(w)) { + cur.push(w); + backtrack(j + 1); + cur.pop(); + } + } + }; + + backtrack(0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n * 2 ^ n)$ +* Space complexity: $O(m + 2 ^ n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. + +--- + +## 2. Backtracking + Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = {} + self.isWord = False + +class Trie: + def __init__(self): + self.root = TrieNode() + + def addWord(self, word): + curr = self.root + for c in word: + if c not in curr.children: + curr.children[c] = TrieNode() + curr = curr.children[c] + curr.isWord = True + +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> List[str]: + trie = Trie() + for word in wordDict: + trie.addWord(word) + + def backtrack(i, path): + if i == len(s): + res.append(" ".join(path)) + return + + node = trie.root + word = [] + for i in range(i, len(s)): + char = s[i] + if char not in node.children: + break + + word.append(char) + node = node.children[char] + + if node.isWord: + path.append("".join(word)) + backtrack(i + 1, path) + path.pop() + + res = [] + backtrack(0, []) + return res +``` + +```java +class TrieNode { + HashMap children = new HashMap<>(); + boolean isWord = false; +} + +class Trie { + TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void addWord(String word) { + TrieNode curr = root; + for (char c : word.toCharArray()) { + curr.children.putIfAbsent(c, new TrieNode()); + curr = curr.children.get(c); + } + curr.isWord = true; + } +} + +public class Solution { + public List wordBreak(String s, List wordDict) { + Trie trie = new Trie(); + for (String word : wordDict) { + trie.addWord(word); + } + + List res = new ArrayList<>(); + backtrack(0, s, new ArrayList<>(), trie, res); + return res; + } + + private void backtrack(int index, String s, List path, Trie trie, List res) { + if (index == s.length()) { + res.add(String.join(" ", path)); + return; + } + + TrieNode node = trie.root; + StringBuilder word = new StringBuilder(); + for (int i = index; i < s.length(); i++) { + char c = s.charAt(i); + if (!node.children.containsKey(c)) { + break; + } + + word.append(c); + node = node.children.get(c); + + if (node.isWord) { + path.add(word.toString()); + backtrack(i + 1, s, path, trie, res); + path.remove(path.size() - 1); + } + } + } +} +``` + +```cpp +struct TrieNode { + unordered_map children; + bool isWord = false; +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void addWord(const string& word) { + TrieNode* curr = root; + for (char c : word) { + if (!curr->children.count(c)) { + curr->children[c] = new TrieNode(); + } + curr = curr->children[c]; + } + curr->isWord = true; + } +}; + +class Solution { +public: + vector wordBreak(string s, vector& wordDict) { + Trie trie; + for (const string& word : wordDict) { + trie.addWord(word); + } + + vector res; + vector path; + backtrack(0, s, path, trie, res); + return res; + } + +private: + void backtrack(int index, string& s, vector& path, Trie& trie, vector& res) { + if (index == s.size()) { + stringstream ss; + for (int i = 0; i < path.size(); ++i) { + if (i > 0) ss << " "; + ss << path[i]; + } + res.push_back(ss.str()); + return; + } + + TrieNode* node = trie.root; + string word; + for (int i = index; i < s.size(); ++i) { + char c = s[i]; + if (!node->children.count(c)) break; + + word.push_back(c); + node = node->children[c]; + + if (node->isWord) { + path.push_back(word); + backtrack(i + 1, s, path, trie, res); + path.pop_back(); + } + } + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = new Map(); + this.isWord = false; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @return {void} + */ + addWord(word) { + let curr = this.root; + for (const c of word) { + if (!curr.children.has(c)) { + curr.children.set(c, new TrieNode()); + } + curr = curr.children.get(c); + } + curr.isWord = true; + } +} + +class Solution { + /** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ + wordBreak(s, wordDict) { + const trie = new Trie(); + for (const word of wordDict) { + trie.addWord(word); + } + + const res = []; + const backtrack = (index, path) => { + if (index === s.length) { + res.push(path.join(" ")); + return; + } + + let node = trie.root; + let word = ""; + for (let i = index; i < s.length; i++) { + const char = s[i]; + if (!node.children.has(char)) { + break; + } + + word += char; + node = node.children.get(char); + + if (node.isWord) { + path.push(word); + backtrack(i + 1, path); + path.pop(); + } + } + }; + + backtrack(0, []); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n * 2 ^ n)$ +* Space complexity: $O(m + 2 ^ n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. + +--- + +## 3. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> List[str]: + wordDict = set(wordDict) + cache = {} + + def backtrack(i): + if i == len(s): + return [""] + if i in cache: + return cache[i] + + res = [] + for j in range(i, len(s)): + w = s[i:j + 1] + if w not in wordDict: + continue + strings = backtrack(j + 1) + for substr in strings: + sentence = w + if substr: + sentence += " " + substr + res.append(sentence) + cache[i] = res + return res + + return backtrack(0) +``` + +```java +public class Solution { + private Set wordSet; + private Map> cache; + + public List wordBreak(String s, List wordDict) { + wordSet = new HashSet<>(wordDict); + cache = new HashMap<>(); + return backtrack(s, 0); + } + + private List backtrack(String s, int i) { + if (i == s.length()) + return Arrays.asList(""); + if (cache.containsKey(i)) + return cache.get(i); + + List res = new ArrayList<>(); + for (int j = i; j < s.length(); j++) { + String w = s.substring(i, j + 1); + if (!wordSet.contains(w)) + continue; + List strings = backtrack(s, j + 1); + for (String substr : strings) { + String sentence = w; + if (!substr.isEmpty()) + sentence += " " + substr; + res.add(sentence); + } + } + cache.put(i, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + vector wordBreak(string s, vector& wordDict) { + wordSet = unordered_set(wordDict.begin(), wordDict.end()); + cache = unordered_map>(); + return backtrack(s, 0); + } + +private: + unordered_set wordSet; + unordered_map> cache; + + vector backtrack(const string& s, int i) { + if (i == s.size()) + return {""}; + if (cache.count(i)) + return cache[i]; + + vector res; + for (int j = i; j < s.size(); ++j) { + string w = s.substr(i, j - i + 1); + if (!wordSet.count(w)) + continue; + vector strings = backtrack(s, j + 1); + for (const string& substr : strings) { + string sentence = w; + if (!substr.empty()) + sentence += " " + substr; + res.push_back(sentence); + } + } + cache[i] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ + wordBreak(s, wordDict) { + const wordSet = new Set(wordDict); + const cache = new Map(); + + const backtrack = (i) => { + if (i === s.length) { + return [""]; + } + if (cache.has(i)) { + return cache.get(i); + } + + const res = []; + for (let j = i; j < s.length; j++) { + const w = s.substring(i, j + 1); + if (!wordSet.has(w)) continue; + + const strings = backtrack(j + 1); + for (const substr of strings) { + let sentence = w; + if (substr) { + sentence += " " + substr; + } + res.push(sentence); + } + } + cache.set(i, res); + return res; + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n * 2 ^ n)$ +* Space complexity: $O(m + n * 2 ^ n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. + +--- + +## 4. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> List[str]: + wordSet = set(wordDict) + n = len(s) + dp = [[] for _ in range(n + 1)] + dp[0] = [""] + + for i in range(1, n + 1): + for j in range(i): + if s[j:i] in wordSet: + for sentence in dp[j]: + dp[i].append((sentence + " " + s[j:i]).strip()) + + return dp[n] +``` + +```java +public class Solution { + public List wordBreak(String s, List wordDict) { + Set wordSet = new HashSet<>(wordDict); + int n = s.length(); + List[] dp = new ArrayList[n + 1]; + for (int i = 0; i <= n; i++) { + dp[i] = new ArrayList<>(); + } + dp[0].add(""); + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < i; j++) { + if (wordSet.contains(s.substring(j, i))) { + for (String sentence : dp[j]) { + dp[i].add((sentence + " " + s.substring(j, i)).trim()); + } + } + } + } + + return dp[n]; + } +} +``` + +```cpp +class Solution { +public: + vector wordBreak(string s, vector& wordDict) { + unordered_set wordSet(wordDict.begin(), wordDict.end()); + int n = s.size(); + vector> dp(n + 1); + dp[0] = {""}; + + for (int i = 1; i <= n; ++i) { + for (int j = 0; j < i; ++j) { + string word = s.substr(j, i - j); + if (wordSet.count(word)) { + for (const string& sentence : dp[j]) { + if (sentence.empty()) { + dp[i].push_back(word); + } else { + dp[i].push_back(sentence + " " + word); + } + } + } + } + } + + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ + wordBreak(s, wordDict) { + const wordSet = new Set(wordDict); + const n = s.length; + const dp = Array.from({ length: n + 1 }, () => []); + dp[0].push(""); + + for (let i = 1; i <= n; i++) { + for (let j = 0; j < i; j++) { + if (wordSet.has(s.substring(j, i))) { + for (const sentence of dp[j]) { + dp[i].push((sentence + " " + s.substring(j, i)).trim()); + } + } + } + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n * 2 ^ n)$ +* Space complexity: $O(m + n * 2 ^ n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. + +--- + +## 5. Dynamic Programming (Top-Down) Using Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = {} + self.isWord = False + +class Trie: + def __init__(self): + self.root = TrieNode() + + def addWord(self, word): + curr = self.root + for c in word: + if c not in curr.children: + curr.children[c] = TrieNode() + curr = curr.children[c] + curr.isWord = True + +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> List[str]: + trie = Trie() + for word in wordDict: + trie.addWord(word) + + cache = {} + + def backtrack(index): + if index == len(s): + return [""] + if index in cache: + return cache[index] + + res = [] + curr = trie.root + for i in range(index, len(s)): + char = s[i] + if char not in curr.children: + break + curr = curr.children[char] + if curr.isWord: + for suffix in backtrack(i + 1): + if suffix: + res.append(s[index:i + 1] + " " + suffix) + else: + res.append(s[index:i + 1]) + + cache[index] = res + return res + + return backtrack(0) +``` + +```java +class TrieNode { + Map children = new HashMap<>(); + boolean isWord = false; +} + +class Trie { + TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void addWord(String word) { + TrieNode curr = root; + for (char c : word.toCharArray()) { + curr.children.putIfAbsent(c, new TrieNode()); + curr = curr.children.get(c); + } + curr.isWord = true; + } +} + +public class Solution { + public List wordBreak(String s, List wordDict) { + Trie trie = new Trie(); + for (String word : wordDict) { + trie.addWord(word); + } + + Map> cache = new HashMap<>(); + return backtrack(0, s, trie, cache); + } + + private List backtrack(int index, String s, Trie trie, Map> cache) { + if (index == s.length()) { + return Collections.singletonList(""); + } + + if (cache.containsKey(index)) { + return cache.get(index); + } + + List res = new ArrayList<>(); + TrieNode curr = trie.root; + + for (int i = index; i < s.length(); i++) { + char c = s.charAt(i); + if (!curr.children.containsKey(c)) { + break; + } + curr = curr.children.get(c); + if (curr.isWord) { + for (String suffix : backtrack(i + 1, s, trie, cache)) { + if (!suffix.isEmpty()) { + res.add(s.substring(index, i + 1) + " " + suffix); + } else { + res.add(s.substring(index, i + 1)); + } + } + } + } + + cache.put(index, res); + return res; + } +} +``` + +```cpp +struct TrieNode { + unordered_map children; + bool isWord = false; +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void addWord(const string& word) { + TrieNode* curr = root; + for (char c : word) { + if (!curr->children.count(c)) { + curr->children[c] = new TrieNode(); + } + curr = curr->children[c]; + } + curr->isWord = true; + } +}; + +class Solution { +public: + vector wordBreak(string s, vector& wordDict) { + Trie trie; + for (const string& word : wordDict) { + trie.addWord(word); + } + + unordered_map> cache; + return backtrack(0, s, trie, cache); + } + +private: + vector backtrack(int index, string& s, Trie& trie, unordered_map>& cache) { + if (index == s.size()) { + return {""}; + } + + if (cache.count(index)) { + return cache[index]; + } + + vector res; + TrieNode* curr = trie.root; + + for (int i = index; i < s.size(); ++i) { + char c = s[i]; + if (!curr->children.count(c)) { + break; + } + curr = curr->children[c]; + if (curr->isWord) { + for (const string& suffix : backtrack(i + 1, s, trie, cache)) { + if (!suffix.empty()) { + res.push_back(s.substr(index, i - index + 1) + " " + suffix); + } else { + res.push_back(s.substr(index, i - index + 1)); + } + } + } + } + + return cache[index] = res; + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = new Map(); + this.isWord = false; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @return {void} + */ + addWord(word) { + let curr = this.root; + for (const c of word) { + if (!curr.children.has(c)) { + curr.children.set(c, new TrieNode()); + } + curr = curr.children.get(c); + } + curr.isWord = true; + } +} + +class Solution { + /** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ + wordBreak(s, wordDict) { + const trie = new Trie(); + for (const word of wordDict) { + trie.addWord(word); + } + + const cache = new Map(); + + const backtrack = (index) => { + if (index === s.length) { + return [""]; + } + if (cache.has(index)) { + return cache.get(index); + } + + const res = []; + let curr = trie.root; + + for (let i = index; i < s.length; i++) { + const char = s[i]; + if (!curr.children.has(char)) { + break; + } + curr = curr.children.get(char); + if (curr.isWord) { + for (const suffix of backtrack(i + 1)) { + if (suffix) { + res.push(s.slice(index, i + 1) + " " + suffix); + } else { + res.push(s.slice(index, i + 1)); + } + } + } + } + + cache.set(index, res); + return res; + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n * 2 ^ n)$ +* Space complexity: $O(m + n * 2 ^ n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. \ No newline at end of file