###### tags: `grind75`, `week3` # Grind 75 Week 3 # 1. Add Binary :::success - Time: $O(\text{max}(L_a, L_b)+1)$ - Space: $O(\text{max}(L_a, L_b)+1)$ | Runtime | 0 ms Beats 100% | | --- | --- | | Memory | 6.5 MB Beats 37.32% | ```cpp class Solution { public: string addBinary(string a, string b) { short carry=0; int size_a = a.size(), size_b = b.size(); stringstream result; int ai=size_a-1, bi=size_b-1; while(carry || ai >= 0 || bi >= 0) { carry += (ai >= 0 ? a[ai] - '0' : 0) + (bi >= 0 ? b[bi] - '0' : 0); result << (carry%2); carry/=2; ai--; bi--; } string answer = result.str(); reverse(answer.begin(), answer.end()); return answer; } }; ``` ::: :::info # Solution1: BigInt - TC: O(n) - SC: O(n) Explanations 1. Make `a` `b` be treated as binary number In JavaScript, the prefix **`0b`** is used to represent a binary number literal. 2. Use `BigInt` to sum `a` `b` as normal number When we pass this string to the **`BigInt()`** function, it will be converted to a **`BigInt`** integer with the value **`10`**. 3. convert the result back to a binary string using the **`toString()`** method with a base of 2. Why BigInt? - **BigInt is used to represent Integers greater than 2^53 -1.** - The binary number may over the `2^53 - 1`(maximum of Number) ```jsx var addBinary = function(a, b) { const aBin = `0b${a}`; const bBin = `0b${b}`; const sum = BigInt(aBin) + BigInt(bBin); return sum.toString(2); }; // Example // a = 11, b = 1 // aBin = 0b11, BigInt(aBin) = 3n // bBin = 0b1, BigInt(bBin) = 1n // sum = 4n // sum.toString(2) = 100 ``` --- # Solution2 - TC: O(n) - SC: O(1) Explanation Why `parseInt(a.charAt(aLen--)`? - extract the integer value of the current digit in the binary string **`a`** at position **`aLen`**, and decrement **`aLen`**to move to the next digit in the next iteration of the while loop. ```jsx var addBinary = function(a, b) { let aLen = a.length - 1; let bLen = b.length - 1; let carry = 0; let result = ""; while (aLen >= 0 || bLen >= 0 || carry > 0) { let sum = carry; if (aLen >= 0) sum += parseInt(a.charAt(aLen--)); if (bLen >= 0) sum += parseInt(b.charAt(bLen--)); // Calculate the binary digit value of the current sum by taking sum modulo 2 // and prepend it to the result string. ( + result is prepend) result = (sum % 2) + result; carry = Math.floor(sum / 2); } return result; }; ``` ::: # 2. Diameter of Binary Tree :::success - Time: $O(N)$ - Space: $O(N)$ | Runtime | 3 ms Beats 98.73% | | --- | --- | | Memory | 20.9 MB Beats 8.85% | ```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 diameterOfBinaryTree(TreeNode* root) { if(!root) return 0; int d=0; height(root, d); return d; } int height(TreeNode* root, int &d) { if(!root) return 0; int l = height(root->left, d); int r = height(root->right, d); d = max({d, l+r}); return 1 + max({l, r}); } }; ``` ::: :::info # Solution1: BFS - TC: O(n^2) - SC: O(n) ```javascript= var diameterOfBinaryTree = function(root) { if (!root) return 0; let max = 0; let queue = [root]; while (queue.length) { let node = queue.shift(); let leftDepth = getDepth(node.left); let rightDepth = getDepth(node.right); max = Math.max(max, leftDepth + rightDepth); if (node.left) queue.push(node.left); if (node.right) queue.push(node.right); } return max; }; // Asscoiated w/ 104. max depth function getDepth(node) { if (!node) return 0; return Math.max(getDepth(node.left), getDepth(node.right)) + 1; } ``` # Solution2: DFS - TC: O(n) - SC: O(n) ```jsx var diameterOfBinaryTree = function(root) { if (!root) return 0; let max = 0; function getHeight(node) { if (!node) return 0; let leftHeight = getHeight(node.left); let rightHeight = getHeight(node.right); max = Math.max(leftHeight + rightHeight, max); return Math.max(leftHeight, rightHeight) + 1; } getHeight(root); return max; }; ``` ::: # 3. Middle of the Linked List :::success Time: O(N) Space: O(1) ```cpp! /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* middleNode(ListNode* head) { if(!head->next) return head; ListNode * slow= head, * fast=head; while(fast->next && fast->next->next) { slow = slow->next; fast = fast->next->next; } if(fast->next) return slow->next; return slow; } }; ``` ::: :::info # Solution1: Fast & Slow Pointers ( One Pass ) When **`fast`** reaches the end of the linked list, **`slow`** will be at the middle node of the linked list. 1. Start with two pointers **`slow`** and **`fast`** at the head of the linked list. 2. Move **`slow`**one step at a time, and **`fast`** two steps at a time. - TC: O(n) - SC: O(1) - we only need to use two pointers **`slow`** and **`fast`**. ```jsx var middleNode = function(head) { let fast = head; let slow = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } return slow; }; ``` --- # Solution2: Brute Force ( Two Pass ) Get the length of linked-list, then find the middle. - TC: O(n) - SC: O(1) ```jsx var middleNode = function(head) { let count = 0; let current = head; while (current) { count++; current = current.next; } // 中間值有兩個時,直接取下一個,所以無條件進位。 let middle = Math.floor(count/2); current = head; for (let i = 0; i < middle; i++) { current = current.next; } return current; } ``` ::: # 4. Maximum Depth of Binary Tree :::success **4 ms** Beats **93.18%** **18.7 MB** Beats **93.34%** - Time: $O(n)$: - 如果 skewed,一整條走過就會是 n - Space: $O(n)$: - 如果 skewed,一整條走過當下 stack 最多有 n 個 dfs # Code ```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 dfs(TreeNode* root, int depth) { if(!root) { return depth; } int left=depth, right=depth; if(root->left) { left = dfs(root->left, depth+1); } if(root->right) { right = dfs(root->right, depth+1); } return max(left, right); } int maxDepth(TreeNode* root) { if(!root) return 0; return dfs(root, 1); } }; ``` ::: :::info # Solution1: DFS - TC: O(n) - SC: O(n) ```jsx var maxDepth = function(root) { if (!root) return 0; return getHeight(root); }; function getHeight(node) { if (!node) return 0; let leftHeight = getHeight(node.left); let rightHeight = getHeight(node.right); return Math.max(leftHeight, rightHeight) + 1; } // Cleaner var maxDepth = function(root) { if(!root) return 0; return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1; }; ``` --- # Solution2: BFS - TC: O(n) - SC: O(n) ```jsx var maxDepth = function(root) { if (!root) return 0; let levels = 0, queue = [root]; while (queue.length) { // 沒有鎖定的 levelSize,直接在 for loop 中使用 queue.length 的話會變成在計算每層 node 的數量 let levelSize = queue.length; // BFS 的方式 iterate 每個 node for (let i = 0; i < levelSize; i++) { let node = queue.shift(); // 進入下一層,沒得 push 時,代表該 node 的 左 or 右 是空的 if (node.right) queue.push(node.right); if (node.left) queue.push(node.left); } levels++; } return levels; }; ``` ::: # 5. Contains Duplicate :::success T: O(N) S: O(N) ```cpp! class Solution { public: bool containsDuplicate(vector<int>& nums) { unordered_map<int, bool> seen; for(auto &e : nums) { if(seen.count(e)) return true; seen[e] = true; } return false; } }; ``` ::: :::info # Solution1: Hash Table - TC: O(n) - SC: O(n) ```jsx var containsDuplicate = function(nums) { const map = new Map(); for (const num of nums) { if (map.has(num)) return true; map.set(num , 1); } return false; }; ``` :::