# Arrays 101 ###### tags: `LeetCode筆記` ## :memo: Merge Sorted Array (Easy) ![](https://i.imgur.com/HwEK4kX.png) ### 作法 Two pointers <-,<- nums1的長度是m+n 利用兩個變數去分別記錄兩個array現在"從尾部"掃到哪裡,誰大就存誰到nums1裡面(k) **程式碼最後不用檢查while(i>=0)因為數值都是放在num1這個陣列** **時間: O(N)** **空間: O(1)** ``` class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { int i = m - 1; int j = n - 1; int k = nums1.size() - 1; while (i >= 0 && j >= 0) { if (nums1[i] > nums2[j]) { nums1[k--] = nums1[i--]; } else { nums1[k--] = nums2[j--]; } } while (j >= 0) { nums1[k--] = nums2[j--]; } } }; ``` ## :memo: Sort Array By Parity (Easy) 偶數數字要在奇數數字前,偶數奇數數字堆順序不計 ![](https://hackmd.io/_uploads/SJbPQIsn2.png) ### 作法 Two pointers -><- 頭尾比較互換,頭找到奇,尾找到偶互換 **時間: O(N)** **空間: O(1)** **best** ``` class Solution { vector<int> sortArrayByParity(vector<int>& nums) { int i = 0; int j = nums.size() - 1; while (i < j) { if (nums[i] % 2 > nums[j] % 2) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } if (nums[i] % 2 == 0) i++; if (nums[j] % 2 == 1) j--; } return nums; } } ``` ## :memo: Squares of a Sorted Array (Easy) ![](https://i.imgur.com/2xb4ek6.png) ### 作法 Two pointers -><- **時間: O(N)** **空間: O(N)** ``` class Solution { public: vector<int> sortedSquares(vector<int>& nums) { int n = nums.size(); vector<int> result(n); int left = 0; int right = n - 1; for (int i = n - 1; i >= 0; i--) { int square; if (abs(nums[left]) < abs(nums[right])) { square = nums[right]; right--; } else { square = nums[left]; left++; } result[i] = square * square; } return result; } }; ``` ## :memo: Remove Element (Easy) ![](https://i.imgur.com/BVI3CbC.png) ### 作法 Two pointers ->-> ``` class Solution { public: int removeElement(vector<int>& nums, int val) { int i = 0; int k = 0; for (i = 0; i < nums.size(); i++) { if (nums[i] != val) { // 不能跟"val"一樣 nums[k] = nums[i]; k++; } } return k; } }; ``` ## :memo: Remove Duplicates from Sorted Array (Easy) ![](https://hackmd.io/_uploads/SJmgP_i3n.png) ### 作法 Two pointers ->-> ``` class Solution { public: int removeDuplicates(vector<int>& nums) { int insertIndex = 1; for (int i = 1; i < nums.size(); i++) { if (nums[i - 1] != nums[i]) { //不能跟"前一項"一樣 nums[insertIndex++] = nums[i]; } } return insertIndex; } }; ``` ## :memo: Third Maximum Number (Easy) https://leetcode.com/problems/third-maximum-number/solutions/2614958/official-solution/ Given an integer array nums, return the third distinct maximum number in this array. If the third maximum does not exist, return the maximum number. ### 作法 Min Heap 用一個大小裝三個的min heap去追蹤前三大,top會代表第三大的元素,第一第二不一定 當有比top還大就push掉舊top,insert新的,直到掃過所有元素,這個方法比Max-Heap還要節省空間 **時間: O(N)** **空間: O(1)** ``` class Solution { public: int thirdMax(vector<int>& nums) { priority_queue<int, vector<int>, greater<int>> minHeap; unordered_set<int> taken; for (int index = 0; index < nums.size(); ++index) { // If current number was already taken, skip it. if (taken.count(nums[index])) { continue; } // If min heap already has three numbers in it. // Pop the smallest if current number is bigger than it. if (minHeap.size() == 3) { if (minHeap.top() < nums[index]) { taken.erase(minHeap.top()); minHeap.pop(); minHeap.push(nums[index]); taken.insert(nums[index]); } } // If min heap does not have three number we can push it. else { minHeap.push(nums[index]); taken.insert(nums[index]); } } // 'nums' has only one distinct element it will be the maximum. if (minHeap.size() == 1) { return minHeap.top(); } // 'nums' has two distinct elements. else if (minHeap.size() == 2) { // int firstNum = minHeap.top(); // minHeap.pop(); // return max(firstNum, minHeap.top()); minHeap.pop(); return minHeap.top(); } return minHeap.top(); } }; ``` ### 作法 Sorted set ``` class Solution { public: int thirdMax(vector<int>& nums) { // Sorted set to keep elements in sorted order. set<int> sortedNums; // Iterate on all elements of 'nums' array. for (int& num : nums) { // Do not insert same element again. if (sortedNums.count(num)) { continue; } // If sorted set has 3 elements. if (sortedNums.size() == 3) { // And the smallest element is smaller than current element. if (*sortedNums.begin() < num) { // Then remove the smallest element and push the current element. sortedNums.erase(sortedNums.begin()); sortedNums.insert(num); } } // Otherwise push the current element of nums array. else { sortedNums.insert(num); } } // If sorted set has three elements return the smallest among those 3. if (sortedNums.size() == 3) { return *sortedNums.begin(); } // Otherwise return the biggest element of nums array. return *sortedNums.rbegin(); } }; ``` ### 作法 Three pointers 1. 用long long的最小值 ``` long long firstMax = numeric_limits<long long>::min(); long long secondMax = numeric_limits<long long>::min(); long long thirdMax = numeric_limits<long long>::min(); ``` 2. 用pair<int, bool> ``` pair<int, bool> firstMax = {-1, false}; pair<int, bool> secondMax = {-1, false}; pair<int, bool> thirdMax = {-1, false}; ``` ## :memo: Duplicate Zeros (Easy) ![](https://i.imgur.com/jcArJFq.png) ### 作法 Two pass **時間: O(N)** **空間: O(1)** ``` class Solution { public void duplicateZeros(int[] arr) { int possibleDups = 0; int length_ = arr.size() - 1; // Find the number of zeros to be duplicated // Stopping when left points beyond the last element in the original array // which would be part of the modified array for (int left = 0; left <= length_ - possibleDups; left++) { // Count the zeros if (arr[left] == 0) { // Edge case: This zero can't be duplicated. We have no more space, // as left is pointing to the last element which could be included if (left == length_ - possibleDups) { // For this zero we just copy it without duplication. arr[length_] = 0; length_ -= 1; break; } possibleDups++; } } // Start backwards from the last element which would be part of new array. int last = length_ - possibleDups; // Copy zero twice, and non zero once. for (int i = last; i >= 0; i--) { if (arr[i] == 0) { arr[i + possibleDups] = 0; possibleDups--; arr[i + possibleDups] = 0; } else { arr[i + possibleDups] = arr[i]; } } } } ``` ## :memo: Check If N and Its Double Exist (Easy) Given an array arr of integers, check if there exist two indices i and j such that: 1\. i != j 2\. 0 <= i, j < arr.length 3\. arr[i] == 2 * arr[j] ![](https://i.imgur.com/TRTKrbw.png) ### 作法 用unordered_map<int, int> hash去紀錄是否有符合條件的hash[i]>0 條件: i % 2 == 0 && hash[i / 2] > 0) || hash[2 * i] > 0 ``` class Solution { public: bool checkIfExist(vector<int>& arr) { unordered_map<int, int> hash; for (int i : arr) { if ((i % 2 == 0 && hash[i / 2] > 0) || hash[2 * i] > 0) { return true; } hash[i]++; } return false; } }; ``` ## :memo: Valid Mountain Array (Easy) ![](https://i.imgur.com/8Jwi5Kb.png) ### 作法 1. 一開始檢查第一種情況: 1.陣列size為一回傳false 2. 接著檢查第二種情況: 1.頭尾比鄰近高回傳false 3. 接著檢查第三種情況: 1.從頭往尾直到i比i+1還高回傳false 2.從尾往頭直到j比j-1還高回傳false 4. 然後最後確認檢查i是否等於j: 1.是就回傳true 2.不是就回傳false ``` class Solution { public: bool validMountainArray(vector<int>& arr) { int i = 0; int j = 0; if (arr.size() == 1) { return false; } if (arr[0] >= arr[1] || arr[arr.size() - 1] >= arr[arr.size() - 2]) { return false; } for (i = 0; i < arr.size() - 1; i++) { if (arr[i] >= arr[i + 1]) { break; } } for (j = arr.size() - 1; j > 0; j--) { if (arr[j] >= arr[j - 1]) { break; } } if (i == j) { return true; } return false; } }; ``` ## :memo: Replace Elements with Greatest Element on Right Side (Easy) ![](https://i.imgur.com/ScBOIN0.png) ### 作法 這題要**從尾巴arr.size() - 1開始往前跑**,並且用temp和maximum去swap ``` class Solution { public: vector<int> replaceElements(vector<int>& arr) { int maximum = -1; int temp = 0; for (int i = arr.size() - 1; i >= 0; i--) { temp = arr[i]; arr[i] = maximum; maximum = max(maximum, temp); } return arr; } }; ``` ## :memo: Move Zeroes (Easy) ![](https://i.imgur.com/xoAul8T.png) ### 作法 1 (Space Sub-Optimal) **時間: O(N)** **空間: O(N)** 宣告一個同大小的陣列去存正確答案的再assign給nums ``` void moveZeroes(vector<int>& nums) { int n = nums.size(); // Count the zeroes int numZeroes = 0; for (int i = 0; i < n; i++) { numZeroes += (nums[i] == 0); } // Make all the non-zero elements retain their original order. vector<int> ans; for (int i = 0; i < n; i++) { if (nums[i] != 0) { ans.push_back(nums[i]); } } // Move all zeroes to the end while (numZeroes--) { ans.push_back(0); } // Combine the result for (int i = 0; i < n; i++) { nums[i] = ans[i]; } } ``` ### 作法 2 (Space Optimal, Operation Sub-Optimal) **時間: O(N)** **空間: O(1)** 利用一個變數lastNonZeroFoundAt記錄不是0的數字有幾個,記錄同時一樣從頭往前擺不是0的數字,最後從lastNonZeroFoundAt開始往後擺0,**i會跑得比lastNonZeroFoundAt還快** ``` void moveZeroes(vector<int>& nums) { int lastNonZeroFoundAt = 0; // If the current element is not 0, then we need to // append it just in front of last non 0 element we found. for (int i = 0; i < nums.size(); i++) { if (nums[i] != 0) { nums[lastNonZeroFoundAt++] = nums[i]; } } // After we have finished processing new elements, // all the non-zero elements are already at beginning of array. // We just need to fill remaining array with 0's. for (int i = lastNonZeroFoundAt; i < nums.size(); i++) { nums[i] = 0; } } ``` ### 作法 3 (Optimal) **時間: O(N) However, the total number of operations are optimal.** **空間: O(1)** 兩個變數lastNonZeroFoundAt,cur寫在一個for迴圈 ``` void moveZeroes(vector<int>& nums) { for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) { if (nums[cur] != 0) { swap(nums[lastNonZeroFoundAt++], nums[cur]); } } } ``` ## :memo: Find All Numbers Disappeared in an Array (Easy) ![](https://i.imgur.com/I7Fyuph.png) ### 作法 1 Hash Table ``` class Solution { public: vector<int> findDisappearedNumbers(vector<int>& nums) { vector<int> hashtable(nums.size(), 0); vector<int> res; for (int i = 0; i < nums.size(); i++) { hashtable[nums[i] - 1] = 1; } for (int i = 0; i < hashtable.size(); i++) { if (hashtable[i] == 0) { res.push_back(i + 1); } } return res; } }; ``` ### 作法 2 O(1) Space InPlace Modification Solution **時間: O(N)** **空間: O(1)** 當遇到數值多少就去把(index=數值-1)內的數字*(-1), 最後去看哪些index內的數字為正數, 數字為正數的index值+1是缺少的數值 ![](https://i.imgur.com/9VQsHiA.png) ![](https://i.imgur.com/nTCNB9D.png) ![](https://i.imgur.com/vvMwae9.png) ``` class Solution { public: vector<int> findDisappearedNumbers(vector<int>& nums) { // Iterate over each of the elements in the original array for (int i = 0; i < nums.size(); i++) { // Treat the value as the new index int newIndex = abs(nums[i]) - 1; // Check the magnitude of value at this new index // If the magnitude is positive, make it negative // thus indicating that the number nums[i] has // appeared or has been visited. if (nums[newIndex] > 0) { nums[newIndex] *= -1; } } // Response array that would contain the missing numbers vector<int> result; // Iterate over the numbers from 1 to N and add all those // that have positive magnitude in the array for (int i = 1; i <= nums.size(); i++) { if (nums[i - 1] > 0) { result.push_back(i); } } return result; } }; ``` ## :memo: Max Consecutive Ones II (Medium) Given a binary array nums, return the maximum number of consecutive 1's in the array if you can flip at most one 0. ![](https://i.imgur.com/6t10T2b.png) ### 作法 利用變數index_zero去記錄目前所要計算的1序列中的遇到的第一個0所在的index,並同時記錄temp為暫時1序列的長度,並把flag設為1,表示不會再去把遇到的第二個0的index標為zero_index,如果遇到第二個0,temp--,並判斷temp是否為max_consecu,是就更新,並把3個變數初始化為0,同時也要去判斷是否掃到底,到底要break,以上為同一個if-else if,最後又另一個if去判斷temp是否為max_consecu。 ``` int findMaxConsecutiveOnes(int* nums, int numsSize) { int index_zero = 0; int max_consecu = 0; int temp = 0; int flag = 0; for (int i = 0; i < numsSize; i++) { temp++; if (nums[i] == 0 && !flag) { index_zero = i; flag = 1; } else if (nums[i] == 0) { temp--; if (temp > max_consecu) { max_consecu = temp; } i = index_zero; index_zero = 0; flag = 0; temp = 0; } else if (i == numsSize - 1) { if (temp > max_consecu) { max_consecu = temp; printf("%d\n", max_consecu); } break; } if (temp > max_consecu) { max_consecu = temp; } } return max_consecu; } ``` ### 作法 Sliding window ``` class Solution { public: int findMaxConsecutiveOnes(vector<int>& nums) { int longestSequence = 0; int left = 0; int right = 0; int numZeroes = 0; // while our window is in bounds while (right < nums.size()) { // add the right most element into our window if (nums[right] == 0) { numZeroes++; } // if our window is invalid, contract our window 不能有連續兩個0 while (numZeroes == 2) { if (nums[left] == 0) { numZeroes--; } left++; } // update our longest sequence answer longestSequence = max(longestSequence, right - left + 1); // expand our window right++; } return longestSequence; } }; ``` ## :memo: Product of Array Except Self (Medium) Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i]. The product of any prefix or suffix of nums is **guaranteed** to fit in a **32-bit** integer. You must write an algorithm that runs in O(n) time and without using the division operation. ![image.png](https://hackmd.io/_uploads/B1J4Q_kXa.png) ### 作法 如果nums[i]==0就要有另一個處理:重算leftsum和prefixsum ``` class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { vector<int> ans; int prefixSum = 1; int ProductOfAll = 1; for (int n : nums) { ProductOfAll *= n; } for (int i = 0; i < nums.size(); i++) { int remain = 0; if (nums[i] != 0) { remain = ProductOfAll * prefixSum / nums[i]; ProductOfAll /= nums[i]; prefixSum *= nums[i]; ans.push_back(remain); } else { ProductOfAll = 1; prefixSum = 1; for (int j = i + 1; j < nums.size(); j++) { ProductOfAll *= nums[j]; } for (int j = i - 1; j >= 0; j--) { prefixSum *= nums[j]; } remain = ProductOfAll * prefixSum; prefixSum *= nums[i]; ans.push_back(remain); } } return ans; } }; ``` ## :memo: 刷題檢討 1. 在寫程式之前花時間用筆去寫完整個code 2. 盡量減少使用debugger的次數,用紙筆去trace 3. 整體都是Easy難度,寫Easy難度的題目必須要做到時間花費少以及錯誤次數降低才行, **多宣告變數去降低時間複雜度**,面試要想想一些follow-up ### 各種陣列解題技巧使用時機 #### Two pointers 1. 已先做好大小排序 2. 不計較output的大小排序 #### Two pass 1. 需要擁有陣列的特定元素資訊才能操作陣列的情境下 #### Sliding window 1. 檢查陣列的小片段 #### 利用Input的陣列 1. 回傳值不是Input的陣列