###### tags: `grind75`, `week1` # Grind 75 Week2 # 1. [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/solutions/) :::success # Recursive - Time: $O(N)$:若都是 valid,每個節點都要走過 - Space: $O(logN)$:同一時間 stack 最多就是一條 path 從 root 到 leaf。 | Runtime | 11 ms Beats 81.53% | | --- | --- | | Memory | 21.6 MB Beats 13.31% | ```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: // abs(heightLeft - heightRight) <= 1 bool isBalanced(TreeNode* root) { if(!root) return true; return heightOfInvalid(root) != -1; } int heightOfInvalid(TreeNode * root) { if(!root->left && !root->right) return 1; int leftHeight = heightOfInvalid(root->left); int rightHeight = heightOfInvalid(root->right); if (leftHeight < 0) return -1; if (rightHeight < 0) return -1; if (abs(leftHeight - rightHeight) > 1) return -1; return 1 + max({leftHeight, rightHeight}); } }; ``` ::: :::info # DFS - TC: O(n) - SC: O(n) ```javascript! var isBalanced = function(root) { if (!root) return true; // -1 is the unbalanced situation return getHeight(root) !== -1; } function getHeight(root) { if (!root) return 0; let leftHeight = getHeight(root.left); let rightHeight = getHeight(root.right); // if already unbalanced, return if (leftHeight == -1 || rightHeight == -1) return -1; // if unbalanced, return if (Math.abs(leftHeight - rightHeight) > 1) return -1; // reutrn the height of this subtree return Math.max(leftHeight, rightHeight) + 1; } ``` ::: # 2. Linked List Cycle :::success ## Loop - Time: $O(n)$ - Space: $O(1)$ | Runtime | 7 ms Beats 95.27% | | --- | --- | | Memory | 8.2 MB Beats 49.43% | ```cpp /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool hasCycle(ListNode *head) { if(!head || !head->next) return false; ListNode* slow = head; ListNode* fast = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; } }; ``` ::: :::info # Hash Table - TC: O(n) - SC: O(n) ```jsx const hasCycle = function(head) { const seen = new Set(); while (head) { if (seen.has(head)) return true; seen.add(head); head = head.next; } return false; }; ``` ::: # 3. Implement Queue using Stacks :::success # 解法 放東西進去 stack 前先倒出來到 stack2,放新的到 stack 最下面,再把 stack2 倒回去 - Time: $O(n)$ - Space: $O(n)$ ```cpp class MyQueue { public: stack<int> s; MyQueue() { } void push(int x) { stack<int> tmp; while(!s.empty()) { int top = s.top(); tmp.push(top); s.pop(); } s.push(x); while(!tmp.empty()) { int top = tmp.top(); s.push(top); tmp.pop(); } } int pop() { int top = s.top(); s.pop(); return top; } int peek() { return s.top(); } bool empty() { return s.empty(); } }; /** * Your MyQueue object will be instantiated and called as such: * MyQueue* obj = new MyQueue(); * obj->push(x); * int param_2 = obj->pop(); * int param_3 = obj->peek(); * bool param_4 = obj->empty(); */ ``` ::: :::info - TC: O(1) for push(), O(n) for pop(), peek(), empty() - SC: O(n) ```javascript! var MyQueue = function() { this.stack1 = []; this.stack2 = []; }; MyQueue.prototype.push = function(x) { this.stack1.push(x); }; MyQueue.prototype.pop = function() { if (this.stack2.length === 0) { while (this.stack1.length > 0) { this.stack2.push(this.stack1.pop()); } } return this.stack2.pop(); }; MyQueue.prototype.peek = function() { if (this.stack2.length === 0) { while (this.stack1.length > 0) { this.stack2.push(this.stack1.pop()); } } return this.stack2[this.stack2.length - 1]; }; MyQueue.prototype.empty = function() { return (this.stack1.length === 0 && this.stack2.length === 0); }; ``` ::: # 4. First Bad Version :::success ## Binary Search - Time: $O(logN)$ - Space: $O(1)$ | Runtime | 3 ms Beats 46.4% | | --- | --- | | Memory | 5.9 MB Beats 57.41% | ```cpp class Solution { public: int firstBadVersion(int n) { int s = 1, e = n; int mid; bool bad; while(s <= e) { // 靠腰喔 // mid = (s+e)/2; // signed integer overflow: 1063376696 + 2126753390 cannot be represented in type 'int' mid = s + (e-s)/2; bad = isBadVersion(mid); if(bad) { e = mid-1; } else { s = mid+1; } } if(bad) { return mid; } else { return mid+1; } } }; ``` ::: :::info # Binary Search - TC: O(logn) - SC: O(1) ```javascript! var solution = function(isBadVersion) { return function(n) { let left = 1; let right = n; while (left < right) { let mid = Math.floor((left + right) / 2); if (isBadVersion(mid)) { right = mid; } else { left = mid + 1; } } return left; }; }; ``` ::: # 5. Ransom Note :::success ## Complexity - Time: $O(\text{max}(L_r, L_m))$:loop - Space: $O(1)$:fixed 26 array ## Code **15 ms** Beats **68.18%** **8.7 MB** Beats **78.75%** ```cpp class Solution { public: bool canConstruct(string ransomNote, string magazine) { int note[26] = {0}; int mag[26] = {0}; for(int i = 0 ;i < ransomNote.size();i++) { note[ransomNote[i] - 'a']++; } for(int i = 0 ;i < magazine.size();i++) { mag[magazine[i] - 'a']++; } for(int i = 0 ;i < 26;i++) { if(mag[i] < note[i]) return false; } return true; } }; ``` ::: :::info # Hash Table - TC: O(n) - SC: O(n) ```javascript! var canConstruct = function(ransomNote, magazine) { const map = new Map(); for (const char of magazine) { map.has(char) ? map.set(char, map.get(char) + 1) : map.set(char, 1); } for (const char of ransomNote) { if ( !map.get(char) // 判斷字母是否存在 || map.get(char) === 0 // 判斷字母數量是否一致( ransomNote 的要少於等於 magazine ) ) return false; map.set(char, map.get(char) - 1); // 每次進來都扣除原本字母的次數 } return true; }; ``` ::: # 6. Climbing Stairs :::success ## Complexity - Time: $O(n)$ - Space: $O(1)$ ## Code **0 ms** Beats **100%** **6 MB** Beats **49.59%** ```cpp class Solution { public: int climbStairs(int n) { int a[46] = { 0 }; a[1] = 1; a[2] = 2; for(int i = 3 ; i <=n ;i++) { a[i] = a[i-1] + a[i-2]; } return a[n]; } }; ``` ::: :::info # DP - TC: O(n) - SC: O(n) ```javascript! var climbStairs = function(n) { if (n === 1) return 1; let dp = new Array(n + 1); dp[0] = 1; dp[1] = 1; for (let i = 2; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; }; ``` ::: # 7. Longest Palindrome :::success ## Loop - Time: $O(n)$:看過整個 s 一次就結束了 - Space: $O(1)$:fixed-length 52 array **0 ms** Beats **100%** **6.6 MB** Beats **56.78%** ```cpp class Solution { public: int longestPalindrome(string s) { int a[52] = {0}; int left = s.size(); int sum = 0; for(int i = 0;i< s.size();i++) { int index; if(s[i] >= 'a') { index = s[i] - 'a'+26; // 0~26 for A-Z, 27~51 for a-z } else { index = s[i] - 'A'; } a[index]++; if(a[index]==2) { a[index]-=2; sum+=2; left-=2; } } return sum + (left > 0 ? 1 : 0); } }; ``` ::: :::info # Hash Map - TC: O(n) - SC: O(n) ```javascript! var longestPalindrome = function(s) { let freq = new Map(); for (let i = 0; i < s.length; i++) { let c = s.charAt(i); freq.set(c, (freq.get(c) || 0) + 1); } let length = 0; let hasOddFreq = false; for (let [c, f] of freq) { if (f % 2 === 0) { length += f; } else { length += f - 1; hasOddFreq = true; } } return hasOddFreq ? length + 1 : length; }; ``` ::: # 8. Reverse Linked List :::success ## Loop - Time: $O(n)$ - Space: $O(1)$ **3 ms** Beats **95.52%** **8.3 MB** Beats **86.13%** ```cpp class Solution { public: ListNode* reverseList(ListNode* head) { if(!head) return head; ListNode * temp = nullptr; ListNode * prev = nullptr; while(head) { temp = head->next; head->next= prev; prev = head; head = temp; } return prev; } }; ``` ## Recursive - Time: $O(n)$ - Space: $O(n)$ **3 ms** Beats **95.52%** **8.6 MB** Beats **11.14%** ```cpp class Solution { public: ListNode* reverseList(ListNode* head) { if(!head) return head; ListNode* newHead = getNewHead(nullptr, head); return newHead; } ListNode* getNewHead(ListNode* prev, ListNode* head) { if(!head->next) { head->next = prev; return head; } ListNode * newHead = getNewHead(head, head->next); head->next = prev; return newHead; } }; ``` ::: :::info # Brute Force - TC: O(n) - SC: O(1) ```javascript! const reverseList = function(head) { if (!head) return null; let previous = null; let current = head; while (current) { let temp = current.next; current.next = previous; previous = current; current = temp; } return previous; } ``` # List Destructing Assignment ```javascript= const reverseList = function(head) { if (!head) return null; let [prev, curr] = [null, head]; while (curr) { [curr.next, prev, curr] = [prev, curr, curr.next] } return prev; } ``` ::: # 9. Majority Element :::success # Boyer-Moore T:O(n) S:O(1) 24 ms Beats 39.58% 19.6 MB Beats 37.79% ```c++ class Solution { public: int majorityElement(vector<int>& nums) { if(nums.size() == 1) return nums[0]; int cand = nums[0]; int count = 0; for(int i = 0;i<nums.size();i++) { if(nums[i] == cand) count++; else { count--; if(count == 0) { cand = nums[i]; count = 1; } } } return cand; } }; ``` ::: :::info # Boyer-Moore Majority Vote Algorithm - TC: O(n) - SC: O(1) ```javascript= var majorityElement = function(nums) { let major = null, count = 0; for (let i = 0; i < nums.length; i++) { if (count === 0) major = nums[i]; count += nums[i] === major ? 1 : -1; } return major; } ``` :::