# Leetcode刷題學習筆記--map hashmap是一個很好用的資料結構,可以把資料對應成key-value pairs,實際的實做是red-black tree,所以Time complexity為O(logN)。 + map(key會從小到大排序,==字串的話則是依字典序排序==) + unordered_map(key不會排序) + multimap(允許key重複) + unordered_multimap ## Problems ### [496. Next Greater Element I(Easy)](https://leetcode.com/problems/next-greater-element-i/) 給定兩個array,nums1和nums2。其中nums1為nums2的子集合。找出nums1[i]在nums2出現的位置以後,第一個大於nums1[i]的值,如果沒有return -1。範例如下: >Input: nums1 = [4,1,2], nums2 = [1,3,4,2] Output: [-1,3,-1] Explanation: The next greater element for each value of nums1 is as follows: >- 4 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. >- 1 is underlined in nums2 = [1,3,4,2]. The next greater element is 3. >- 2 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. 解題思路: > 1. 使用map建立一個value和position的對應。這樣可以快速找到nums1的值在nums2的位置。 > 2. 找到位置之後,找尋下一個位置到最後大於nums1[i]的值。 ```c++ vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { map<int, int> m; auto nums2_size = nums2.size(); for(int i = 0; i < nums2.size(); ++i) m[nums2[i]] = i; vector<int> rtn; for(auto& n : nums1) { int val = -1; for(int i = m[n] + 1; i < nums2_size; ++i) { if(nums2[i] > n) { val = nums2[i]; break; } } rtn.push_back(val); } return rtn; } ``` ### [454. 4Sum II(Medium)](https://leetcode.com/problems/4sum-ii/) 這類問題除了用[two pointer](/gg-708HfRomJ66P7XX_QKQ)也可以用map來解。 給你四個vector<int> nums1, nums2, nums3, nums4,求出四個vector可以組合出來sum為0。 > 1. 使用map來統計兩兩個和。 > 2. 因為沒賦值得map為零,所以不須再額外判斷是否存在。 ```cpp= int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { auto n = nums1.size(); unordered_map<int, int> m1, m2; for(int i = 0; i < n; ++i) { for(int j = 0; j < n; ++j) { m1[nums1[i] + nums2[j]]++; m2[nums3[i] + nums4[j]]++; } } int rtn{0}; for(auto& a : m1) rtn += a.second * m2[-1 * a.first]; return rtn; } ``` ### [138. Copy List with Random Pointer](https://leetcode.com/problems/copy-list-with-random-pointer/) 給你一個linked list node,除了指向next之外還指向random node,如下。copy所有的node。 ```cpp= class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; ``` > 1. 因為是copy所有的node,所以用map來記錄新舊的對應。 ```cpp= class Solution { unordered_map<Node *, Node *> m; public: Node* copyRandomList(Node* head) { if(!head) return nullptr; if(m.count(head)) return m[head]; // 已經copy過了直接return Node *n = new Node(head->val); m[head] = n; // 紀錄新舊對應 n->random = copyRandomList(head->random); n->next = copyRandomList(head->next); return n; } }; ``` ### [133. Clone Graph](https://leetcode.com/problems/clone-graph/) 和[138](/XfUiK191STCsppXWkgjbXQ#138-Copy-List-with-Random-Pointer)類似,題目改成無向圖。 ```cpp= class Solution { unordered_map<Node *, Node *> m; public: Node* cloneGraph(Node* node) { if(!node) return nullptr; if(m.count(node)) return m[node]; Node *n = new Node(node->val); m[node] = n;; for(Node *adj : node->neighbors) { n->neighbors.push_back(cloneGraph(adj)); } return n; } }; ``` ### [36. Valid Sudoku](https://leetcode.com/problems/valid-sudoku/) 使用客製的key來統計是否有資料重複在row, column和block中重複出現。 ```cpp= bool isValidSudoku(vector<vector<char>>& board) { unordered_set<string> s; for(int y = 0; y < 9; ++y) { for(int x = 0; x < 9; ++x) { if(!isdigit(board[y][x])) continue; string row = "r" + to_string(y) + "-" + board[y][x]; string col = "c" + to_string(x) + "-" + board[y][x]; string blk = "b" + to_string((y / 3) * 3 + (x / 3)) + "-" + board[y][x]; if(s.count(row) || s.count(col) || s.count(blk)) return false; s.insert(row); s.insert(col); s.insert(blk); } } return true; } ``` time complexity : 每一次的count為$O(logN)$,所以為$O(3logN)$, 每一次的insert為$O(logN)$,所以也是$O(3logN)$, 其中N為board的全部element數目($N = m * n$)。 所以$O(N * (3logN + 3logN)) = O(6NlogN) = O(NlogN)$ space complexity : $O(N)$,使用一個set紀錄全部的element。 ### [652. Find Duplicate Subtrees](https://leetcode.com/problems/find-duplicate-subtrees/) 這題和[297. Serialize and Deserialize Binary Tree](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/)類似。 ==客製key,把BST變成string,就可以用map來記錄是否有重複的BST。== ```cpp= string helper(TreeNode *root, unordered_map<string, int>& m, vector<TreeNode *>& rtn) { if(!root) return "#"; string cur = to_string(root->val) + " " + helper(root->left, m, rtn) + " " + helper(root->right, m, rtn); if(m[cur] == 1) rtn.push_back(root); m[cur]++; return cur; } vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) { vector<TreeNode *> rtn; unordered_map<string, int> m; helper(root, m, rtn); return rtn; } ``` ### [923. 3Sum With Multiplicity](https://leetcode.com/problems/3sum-with-multiplicity/) 一個數列中,找出nums[i] + nums[j] + nums[k] == target的所有組合數,其中i < j 且 j < k。數列中會有重複的數字。 > 1. 使用map來統計所以數的出現次數。 > 2. 使用兩個for來traverse map。 > 3. 三種情況, > + 三個數都一樣 > + 兩個數一樣,一個不一樣 > + 三個數都不一樣。 ``` int threeSumMulti(vector<int>& arr, int target) { map<int, long> m; for(auto& n : arr) m[n]++; long rtn = 0; for(auto it1 = m.begin(); it1 != m.end(); ++it1 ) { for(auto it2 = it1; it2 != m.end(); ++it2) { int i = it1->first, j = it2->first, k = target - i - j; if(!m.count(k)) continue; // 三個都一樣 if(i == j && j == k) rtn += (m[i] * (m[i] - 1) * (m[i] - 2)) / 6; // 兩個一樣,一個不一樣,包括(1, 2, 2)或是(2, 2, 3) else if(i == j && j != k) rtn += (m[i] * (m[i] - 1)) / 2 * m[k]; // 三個都不一樣 // 因為不照順序會有重複的問題 else if(i < j && j < k) rtn += m[i] * m[j] * m[k]; } } return rtn % (long)(1e9 + 7); } ``` ### [128. Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/) 給你一個vector<int>,求出最長的連續數字的長度。 > 1. 使用unordered_map來記錄,每個數字的長度。 > 2. 如果目前的數字有旁邊的數,就把他接起來。並且更新最前面和最後面的長度。 > 3. 如果兩邊都有數字,就把兩邊的長度加起來再加一,一樣更新最前面和最後面的長度。 ```cpp= int longestConsecutive(vector<int>& nums) { int sz = nums.size(); if(sz <= 1) return sz; unordered_map<int, int> m; int maxlen = 1; for(auto& n : nums) { if(m.count(n)) continue; else if(m.count(n - 1) && m.count(n + 1)) m[n] = m[n + m[n + 1]] = m[n - m[n - 1]] = m[n + 1] + m[n - 1] + 1; else if(m.count(n - 1)) m[n] = m[n - m[n - 1]] = m[n - 1] + 1; else if(m.count(n + 1)) m[n] = m[n + m[n + 1]] = m[n + 1] + 1; else m[n] = 1; maxlen = max(maxlen, m[n]); } // time : O(N) // space : O(N) return maxlen; } ``` ### [41. First Missing Positive](https://leetcode.com/problems/first-missing-positive/description/) 給你一個vector<int> nums找出第一個missing positive。 > + 因為題目要求找出 missing positive,所以negtive用不到 > + 因為array的長度為sz,所以假設array都塞滿positive,則[1, 2, 3, ..., sz], 答案一定是在[1, sz + 1] 之間 > + 使用index當成key,則0用不到,sz沒辦法用。所以把0當成sz > + 當我們把negative或是n > sz換成1,則==數值的正負可以用來當成是否有找到數值的代表== > + space : O(1), 只能使用固定長度的variable或是運用input本身。 ```cpp= class Solution { public: int firstMissingPositive(vector<int>& nums) { int sz = nums.size(); int containOne = 0; for(auto& n : nums) { if(n == 1) { containOne = 1; break; } } if(containOne == 0) return 1; for(auto& n : nums) if(n <= 0 || n > sz) n = 1; for(int i = 0; i < sz; ++i) { int a = abs(nums[i]); if(a == sz) nums[0] = -abs(nums[0]); else nums[a] = -abs(nums[a]); } for(int i = 1; i < sz; ++i) { if(nums[i] > 0) return i; } if(nums[0] > 0) return sz; // 少了sz else return sz + 1; // } }; ``` ###### tags: `leetcode` `刷題`