Apply Operations to an Array
EasyPrompt
You are given a 0-indexed array nums of size n consisting of non-negative integers.
You need to apply n - 1 operations to this array where, in the ith operation (0-indexed), you will apply the following on the ith element of nums:
- If
nums[i] == nums[i + 1], then multiplynums[i]by2and setnums[i + 1]to0. Otherwise, you skip this operation.
After performing all the operations, shift all the 0's to the end of the array.
- For example, the array
[1,0,2,0,0,1]after shifting all its0's to the end, is[1,2,1,0,0,0].
Return the resulting array.
Note that the operations are applied sequentially, not all at once.
Example 1:
Input: nums = [1,2,2,1,1,0]
Output: [1,4,2,0,0,0]
Explanation: We do the following operations:
- i = 0: nums[0] and nums[1] are not equal, so we skip this operation.
- i = 1: nums[1] and nums[2] are equal, we multiply nums[1] by 2 and change nums[2] to 0. The array becomes [1,4,0,1,1,0].
- i = 2: nums[2] and nums[3] are not equal, so we skip this operation.
- i = 3: nums[3] and nums[4] are equal, we multiply nums[3] by 2 and change nums[4] to 0. The array becomes [1,4,0,2,0,0].
- i = 4: nums[4] and nums[5] are equal, we multiply nums[4] by 2 and change nums[5] to 0. The array becomes [1,4,0,2,0,0].
After that, we shift the 0's to the end, which gives the array [1,4,2,0,0,0].Example 2:
Input: nums = [0,1]
Output: [1,0]
Explanation: No operation can be applied, we just shift the 0 to the end.
Constraints:
2 <= nums.length <= 20000 <= nums[i] <= 1000
Approaches
3 approaches with complexity analysis and trade-offs.
This approach directly simulates the problem statement in two distinct phases. First, it applies all the operations on the input array. Second, it creates a new array and populates it with the non-zero elements from the modified input array, effectively shifting all zeros to the end.
Algorithm
-
- Iterate from
i = 0ton-2on thenumsarray.
- Iterate from
-
- If
nums[i]equalsnums[i+1], updatenums[i] = nums[i] * 2andnums[i+1] = 0.
- If
-
- Create a new integer array
resultof sizen.
- Create a new integer array
-
- Initialize a
writeIndexto 0.
- Initialize a
-
- Iterate through the modified
numsarray.
- Iterate through the modified
-
- If the current element
numis not 0, setresult[writeIndex] = numand incrementwriteIndex.
- If the current element
-
- Return the
resultarray.
- Return the
Walkthrough
Phase 1: Apply Operations
We iterate through the nums array from the first element up to the second-to-last element (i from 0 to n-2). In each iteration, we check if nums[i] is equal to nums[i+1]. If they are equal, we double nums[i] and set nums[i+1] to zero. This is done in-place on the original nums array.
Phase 2: Shift Zeros
We create a new array, result, of the same size n, which is by default initialized with zeros in Java. We use a pointer, writeIndex, initialized to 0, to keep track of the next position to fill in the result array. We iterate through the modified nums array. For each element, if it's not zero, we copy it to result[writeIndex] and increment writeIndex. After iterating through all elements of nums, the result array will contain all non-zero elements at the beginning, followed by zeros.
class Solution { public int[] applyOperations(int[] nums) { int n = nums.length; // Phase 1: Apply operations for (int i = 0; i < n - 1; i++) { if (nums[i] == nums[i + 1]) { nums[i] *= 2; nums[i + 1] = 0; } } // Phase 2: Shift zeros to the end using an extra array int[] result = new int[n]; int writeIndex = 0; for (int num : nums) { if (num != 0) { result[writeIndex++] = num; } } return result; }}Complexity
Time
O(n) - The first loop runs `n-1` times, and the second loop runs `n` times. This gives a total time complexity of O(n-1 + n) which simplifies to O(n).
Space
O(n) - We use an additional array `result` of size `n` to store the final arrangement.
Trade-offs
Pros
Simple to understand and implement as it directly follows the problem description's two steps.
Cons
Uses extra space proportional to the input size, which is inefficient for large arrays.
This approach improves upon the previous one by eliminating the need for an extra array. It still performs the two main steps sequentially, but the second step (shifting zeros) is done in-place, thus saving space.
Algorithm
-
- Iterate from
i = 0ton-2on thenumsarray.
- Iterate from
-
- If
nums[i]equalsnums[i+1], updatenums[i] = nums[i] * 2andnums[i+1] = 0.
- If
-
- Initialize a
writeIndexto 0.
- Initialize a
-
- Iterate through
numsfromi = 0ton-1.
- Iterate through
-
- If
nums[i]is not 0, setnums[writeIndex] = nums[i]and incrementwriteIndex.
- If
-
- Iterate from
writeIndexton-1.
- Iterate from
-
- Set
nums[i] = 0for each element in this range.
- Set
-
- Return the modified
numsarray.
- Return the modified
Walkthrough
Phase 1: Apply Operations
This phase is identical to the first approach. We iterate from i = 0 to n-2 and apply the specified operations directly on the nums array.
Phase 2: Shift Zeros In-Place
We use a "write pointer" (writeIndex) to manage the placement of non-zero elements. This pointer starts at index 0. We iterate through the nums array with a "read pointer" (i). Whenever we encounter a non-zero element at nums[i], we move it to the nums[writeIndex] position and then increment writeIndex. This effectively collects all non-zero elements at the beginning of the array, preserving their relative order. After this loop, all non-zero elements are in nums[0...writeIndex-1]. We then perform a second loop from writeIndex to n-1 to fill the remaining positions of the array with zeros.
class Solution { public int[] applyOperations(int[] nums) { int n = nums.length; // Phase 1: Apply operations for (int i = 0; i < n - 1; i++) { if (nums[i] == nums[i + 1]) { nums[i] *= 2; nums[i + 1] = 0; } } // Phase 2: Shift zeros to the end in-place int writeIndex = 0; for (int i = 0; i < n; i++) { if (nums[i] != 0) { nums[writeIndex++] = nums[i]; } } // Fill the rest of the array with zeros while (writeIndex < n) { nums[writeIndex++] = 0; } return nums; }}Complexity
Time
O(n) - The first loop for operations is O(n). The second phase involves two loops that together iterate through the array once, which is also O(n). The total complexity is O(n) + O(n) = O(n).
Space
O(1) - The modifications are done in-place, and we only use a few extra variables for indices, resulting in constant extra space.
Trade-offs
Pros
Space-efficient as it avoids creating a new array, using only constant extra space.
Cons
Requires two separate passes over the array data, which might be slightly less performant than a single-pass solution due to cache effects.
This is the most efficient approach, combining both the operation and zero-shifting steps into a single pass over the array. It modifies the array in-place, using a write pointer to build the final result without needing extra space or multiple passes.
Algorithm
-
- Initialize a
writeIndexto 0.
- Initialize a
-
- Iterate through the
numsarray with a read indexifrom0ton-1.
- Iterate through the
-
- Inside the loop, first check if
i < n-1andnums[i] == nums[i+1]. If so, apply the operation:nums[i] *= 2andnums[i+1] = 0.
- Inside the loop, first check if
-
- After the potential operation, check if the current element
nums[i]is non-zero.
- After the potential operation, check if the current element
-
- If
nums[i]is non-zero, swapnums[i]withnums[writeIndex], and then incrementwriteIndex.
- If
-
- After the loop, the array is in the desired final state. Return
nums.
- After the loop, the array is in the desired final state. Return
Walkthrough
The core idea is to process each element nums[i] and immediately place its final, post-operation value into the correct position in the array. We use a writeIndex pointer, initialized to 0, to track the position for the next non-zero element. We iterate through the array with a read pointer i from 0 to n-1. In each iteration, we first apply the operation if applicable (i.e., if i < n-1). After this, the value of nums[i] is final. If it's non-zero, we swap it into the nums[writeIndex] position. This works because any element at nums[writeIndex] that gets swapped back to nums[i] must be a zero that has already been processed. After the single loop, all non-zero elements are compacted at the front, and the rest of the array is filled with zeros automatically as a result of the swaps.
class Solution { public int[] applyOperations(int[] nums) { int n = nums.length; int writeIndex = 0; for (int i = 0; i < n; i++) { // Apply operation if possible if (i + 1 < n && nums[i] == nums[i + 1]) { nums[i] *= 2; nums[i + 1] = 0; } // If current element is non-zero, move it to the write position if (nums[i] != 0) { // Swap non-zero element to the front int temp = nums[i]; nums[i] = nums[writeIndex]; nums[writeIndex] = temp; writeIndex++; } } return nums; }}Complexity
Time
O(n) - We iterate through the array only once.
Space
O(1) - All operations are performed in-place.
Trade-offs
Pros
Most efficient in both time and space.
It avoids multiple passes over the array, which can improve performance due to better data locality and cache usage.
Cons
The logic is slightly more complex to reason about compared to the two-pass approaches, as operations and shifting are interleaved.
Solutions
Solution
class Solution {public int[] applyOperations(int[] nums) { int n = nums.length; for (int i = 0; i < n - 1; ++i) { if (nums[i] == nums[i + 1]) { nums[i] <<= 1; nums[i + 1] = 0; } } int[] ans = new int[n]; int i = 0; for (int x : nums) { if (x > 0) { ans[i++] = x; } } return ans; }}class Solution: def applyOperations(self, nums: List[int]) -> List[int]: n = len(nums) for i in range(n - 1): if nums[i] == nums[i + 1]: nums[i] <<= 1 nums[i + 1] = 0 ans = [0] * n i = 0 for x in nums: if x: ans[i] = x i += 1 return ansclass Solution {public: vector<int> applyOperations(vector<int> &nums) { int n = nums.size(); for (int i = 0; i < n - 1; ++i) { if (nums[i] == nums[i + 1]) { nums[i] <<= 1; nums[i + 1] = 0; } } vector<int> ans(n); int i = 0; for (int &x : nums) { if (x) { ans[i++] = x; } } return ans; }};Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.