๐งฉ Q1: Merge Sorted Array โ Two Approaches Explained
In this post, weโll dive into solving the classic โMerge Sorted Arrayโ problem from Leetcode. We'll explore two efficient approaches for merging two sorted arrays in-place inside the first one.
โ Problem Statement
You are given two integer arrays:
-
nums1
with a length ofm + n
, where the firstm
elements are valid and the rest are zeros. -
nums2
withn
elements.
Your task is to merge nums2
into nums1
as one sorted array in-place.
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
Output:
nums1 = [1,2,2,3,5,6]
โ Approach 1: Two-Pointer Merge Using Extra Space
This method is intuitive and mimics the merge step of merge sort.
๐ง Step-by-Step Strategy
- Copy the first
m
elements ofnums1
into a temporary array callednums1Copy
.
๐ Why? We will be overwriting
nums1
, so we need to preserve the original values.
-
Use two pointers:
-
p1
fornums1Copy
-
p2
fornums2
-
-
Loop from index
0
tom + n - 1
:- Compare
nums1Copy[p1]
andnums2[p2]
- Assign the smaller one to
nums1[i]
- Move the corresponding pointer
- Compare
โ ๏ธ Edge Case Handling
- If one array is exhausted, continue with the other.
๐ก Why This Works
- We're merging two sorted arrays by comparing their front elements.
- We avoid overwriting data by using a copy of
nums1
. - Simple and easy to understand.
๐ Time & Space Complexity
Complexity | Value | Explanation |
---|---|---|
Time | O(m + n) | Each element is considered once |
Space | O(m) | Temporary array stores original nums1
|
๐จโ๐ป Code (Approach 1)
var merge = function(nums1, m, nums2, n) {
let nums1Copy = nums1.slice(0, m); // Step 1
let p1 = 0, p2 = 0;
for (let i = 0; i < m + n; i++) {
if (p2 >= n || (p1 < m && nums1Copy[p1] < nums2[p2])) {
nums1[i] = nums1Copy[p1++];
} else {
nums1[i] = nums2[p2++];
}
}
};
๐ Example Trace
nums1Copy: [1, 2, 3]
nums2: [2, 5, 6]
Step 1: Compare 1 and 2 โ take 1 โ nums1 = [1, _, _, _, _, _]
Step 2: Compare 2 and 2 โ take 2 (from nums1Copy) โ nums1 = [1, 2, _, _, _, _]
Step 3: Compare 3 and 2 โ take 2 (from nums2) โ nums1 = [1, 2, 2, _, _, _]
Step 4: Compare 3 and 5 โ take 3 โ nums1 = [1, 2, 2, 3, _, _]
Step 5: nums1Copy done โ take 5 โ nums1 = [1, 2, 2, 3, 5, _]
Step 6: โ take 6 โ nums1 = [1, 2, 2, 3, 5, 6]
โ Approach 2: Reverse Two-Pointer (In-Place, No Extra Space)
This approach is more space-efficient and clever. We take advantage of the extra space at the end of nums1
by filling it from the backward.
๐ง Step-by-Step Strategy
-
Initialize three pointers:
-
p1 = m - 1
: last valid element innums1
-
p2 = n - 1
: last element innums2
-
i = m + n - 1
: last position innums1
-
-
Loop backward through
nums1
:- If
p2 < 0
, we're done. - If
nums1[p1] > nums2[p2]
, assignnums1[i] = nums1[p1--]
- Else, assign
nums1[i] = nums2[p2--]
- If
โ No need for additional memory!
๐ก Why This Works
- We're guaranteed that
nums1
has enough space at the end. - Merging from the back avoids overwriting valid values.
- No extra space is used โ fully in-place!
๐ Time & Space Complexity
Complexity | Value | Explanation |
---|---|---|
Time | O(m + n) | Every element is placed once |
Space | O(1) | In-place, no additional memory used |
๐จโ๐ป Code (Approach 2)
var merge = function(nums1, m, nums2, n) {
let p1 = m - 1;
let p2 = n - 1;
for (let i = m + n - 1; i >= 0; i--) {
if (p2 < 0) break;
if (p1 >= 0 && nums1[p1] > nums2[p2]) {
nums1[i] = nums1[p1--];
} else {
nums1[i] = nums2[p2--];
}
}
};
๐ Example Trace
nums1: [1, 2, 3, 0, 0, 0]
nums2: [2, 5, 6]
Start filling from index 5:
Step 1: Compare 3 and 6 โ take 6 โ nums1 = [1, 2, 3, 0, 0, 6]
Step 2: Compare 3 and 5 โ take 5 โ nums1 = [1, 2, 3, 0, 5, 6]
Step 3: Compare 3 and 2 โ take 3 โ nums1 = [1, 2, 3, 3, 5, 6]
Step 4: Compare 2 and 2 โ take 2 (nums2) โ nums1 = [1, 2, 2, 3, 5, 6]
Step 5: Take 2 โ nums1 = [1, 2, 2, 3, 5, 6]
gggggggggg
๐งฉ Q2: Move Zeroes โ Intuition and Efficient Solution Explained
Given an integer array nums, move all 0's to the end of it while maintaining the relative order of the non-zero elements. You must do this in-place without making a copy of the array.
Input:
nums = [0,1,0,3,12]
Output:
nums = [1,3,12,0,0]
โ Approach 1: Using One Pointer (In-Place Overwrite)
We can solve this efficiently by using a single pointer to track the position of non-zero elements.
๐ง Step-by-Step Strategy
Initialize a variable
Pointer
to0
.
๐ This pointer tracks the position where the next non-zero element should go.-
Loop through the array from start to end:
- If the current element is not zero (
nums[i] !== 0
): - Place it at
nums[Pointer]
- Increment
Pointer
- If the current element is not zero (
-
After the loop:
- All non-zero elements are shifted to the front.
- Fill the remaining positions (from
Pointer
tonums.length - 1
) with zeroes.
๐ก Why This Works
- You overwrite the original array in-place without using extra space.
- The order of non-zero elements is preserved.
- All zeroes are moved to the end efficiently.
๐ Time & Space Complexity
Complexity | Value | Explanation |
---|---|---|
Time | O(n) | One pass for shifting, one for filling zeroes |
Space | O(1) | No extra space used |
๐จโ๐ป Code (Approach 1)
var moveZeroes = function(nums) {
if (nums.length < 2) return nums;
let Pointer = 0;
for (let i = 0; i < nums.length; i++) {
if (nums[i] !== 0) {
nums[Pointer] = nums[i];
Pointer++;
}
}
// Fill the rest with zeroes
for (let j = Pointer; j < nums.length; j++) {
nums[j] = 0;
}
return nums;
};
๐ Example Trace
Input
nums = [0, 1, 0, 3, 12]
๐งฎ Step-by-step Execution
- Initial
Pointer = 0
-
i = 0
โ0
โ skip -
i = 1
โ1
โ place at index0
โnums = [1, 1, 0, 3, 12]
โPointer = 1
-
i = 2
โ0
โ skip -
i = 3
โ3
โ place at index1
โnums = [1, 3, 0, 3, 12]
โPointer = 2
-
i = 4
โ12
โ place at index2
โnums = [1, 3, 12, 3, 12]
โPointer = 3
๐งน Fill remaining with zeroes from Pointer = 3
:
-
nums[3] = 0
nums[4] = 0
โ
Final Output:
[1, 3, 12, 0, 0]
Top comments (0)