---
# System prepended metadata

title: 01. Arrays 101
tags: [LeetCode筆記]

---

# 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的陣列