Decompress Run-Length Encoded List
EasyPrompt
We are given a list nums of integers representing a list compressed with run-length encoding.
Consider each adjacent pair of elements [freq, val] = [nums[2*i], nums[2*i+1]] (with i >= 0). For each such pair, there are freq elements with value val concatenated in a sublist. Concatenate all the sublists from left to right to generate the decompressed list.
Return the decompressed list.
Example 1:
Input: nums = [1,2,3,4]
Output: [2,4,4,4]
Explanation: The first pair [1,2] means we have freq = 1 and val = 2 so we generate the array [2].
The second pair [3,4] means we have freq = 3 and val = 4 so we generate [4,4,4].
At the end the concatenation [2] + [4,4,4] is [2,4,4,4].Example 2:
Input: nums = [1,1,2,3]
Output: [1,3,3]
Constraints:
2 <= nums.length <= 100nums.length % 2 == 01 <= nums[i] <= 100
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves iterating through the input array once. For each frequency-value pair, we add the value to a dynamic list (like Java's ArrayList) the specified number of times. This is straightforward but may incur overhead from the list's dynamic resizing.
Algorithm
-
- Create an empty
ArrayListof integers, let's call itresultList.
- Create an empty
-
- Iterate through the input array
numswith a step of 2, from indexi = 0tonums.length - 2.
- Iterate through the input array
-
- In each iteration, get the frequency
freq = nums[i]and the valueval = nums[i+1].
- In each iteration, get the frequency
-
- Start a nested loop that runs
freqtimes.
- Start a nested loop that runs
-
- Inside the nested loop, add
valtoresultList.
- Inside the nested loop, add
-
- After the outer loop finishes, create a new integer array
resultArraywith the same size asresultList.
- After the outer loop finishes, create a new integer array
-
- Copy all elements from
resultListtoresultArray.
- Copy all elements from
-
- Return
resultArray.
- Return
Walkthrough
We initialize an ArrayList to store the decompressed numbers. We then loop through the nums array, taking elements in pairs. The loop iterates from i = 0 to nums.length with a step of 2. For each pair [freq, val], where freq = nums[i] and val = nums[i+1], we run a nested loop freq times. Inside the nested loop, we add val to our ArrayList. After the loops complete, the ArrayList contains the full decompressed list. We then convert this list into an integer array to match the required return type.
import java.util.ArrayList;import java.util.List; class Solution { public int[] decompressRLElist(int[] nums) { List<Integer> resultList = new ArrayList<>(); for (int i = 0; i < nums.length; i += 2) { int freq = nums[i]; int val = nums[i+1]; for (int j = 0; j < freq; j++) { resultList.add(val); } } // Convert List<Integer> to int[] int[] resultArray = new int[resultList.size()]; for (int i = 0; i < resultList.size(); i++) { resultArray[i] = resultList.get(i); } return resultArray; }}Complexity
Time
O(S), where S is the total number of elements in the decompressed list. We iterate through all pairs in `nums` and for each pair `[freq, val]`, we perform `freq` additions. The sum of all `freq` values is `S`. Converting the list to an array also takes O(S) time.
Space
O(S), where S is the size of the decompressed list. This space is required to store the `resultList`.
Trade-offs
Pros
Simple and intuitive to implement.
Requires only a single pass over the input data to generate the list.
Cons
Using a dynamic list like
ArrayListcan lead to performance overhead due to internal array resizing when the capacity is exceeded.Requires an extra step to convert the final
List<Integer>to anint[], which involves another O(S) iteration and memory allocation.
This approach improves upon the dynamic list method by first calculating the exact size of the final decompressed list. It then allocates an array of that specific size and fills it in a second pass. This avoids the overhead of dynamic resizing and is generally more performant.
Algorithm
-
- Initialize a variable
totalSize = 0.
- Initialize a variable
-
- First Pass: Iterate through
numswith a step of 2 (at indices0, 2, 4, ...). In each step, add the frequencynums[i]tototalSize.
- First Pass: Iterate through
-
- Create a new integer array
resultof sizetotalSize.
- Create a new integer array
-
- Initialize an index variable
currentIndex = 0to keep track of the current position in theresultarray.
- Initialize an index variable
-
- Second Pass: Iterate through
numsagain with a step of 2.
- Second Pass: Iterate through
-
- For each pair
[freq, val], wherefreq = nums[i]andval = nums[i+1], fill theresultarray withvalforfreqtimes starting fromcurrentIndex.
- For each pair
-
- Update
currentIndexby addingfreqto it.
- Update
-
- After the loops complete, return the
resultarray.
- After the loops complete, return the
Walkthrough
This method consists of two main passes over the input nums array.
First Pass: The goal is to determine the total length of the decompressed list. We initialize a variable size to 0. We iterate through nums at every even index (i = 0, 2, 4, ...) and add the frequency nums[i] to size.
Array Allocation: After the first pass, size holds the exact number of elements in the final list. We create a new integer array, result, of this length: new int[size].
Second Pass: We fill the newly created result array. We initialize a pointer or index, currentIndex, to 0. We iterate through nums again in pairs ([freq, val]). For each pair, we add val to the result array freq times. This can be done efficiently using java.util.Arrays.fill(). After filling the segment for the current pair, we advance currentIndex by freq.
Finally, we return the populated result array.
import java.util.Arrays; class Solution { public int[] decompressRLElist(int[] nums) { // First pass: calculate the size of the decompressed list int size = 0; for (int i = 0; i < nums.length; i += 2) { size += nums[i]; } // Create the result array with the calculated size int[] result = new int[size]; int currentIndex = 0; // Second pass: fill the result array for (int i = 0; i < nums.length; i += 2) { int freq = nums[i]; int val = nums[i+1]; // Use Arrays.fill for potentially faster block assignment Arrays.fill(result, currentIndex, currentIndex + freq, val); currentIndex += freq; } return result; }}Complexity
Time
O(N + S), where N is the length of the input `nums` array and S is the total number of elements in the decompressed list. The first pass takes O(N) time. The second pass takes O(S) time to fill the array. Thus, the total time complexity is O(N + S).
Space
O(S), for storing the final `result` array. The auxiliary space is O(1) as we only use a few extra variables.
Trade-offs
Pros
More memory-efficient and often faster in practice than the dynamic list approach because it avoids resizing overhead.
Direct array manipulation, especially with
Arrays.fill, can be faster than repeatedArrayList.add()method calls.
Cons
Requires two passes over the input array, which might be considered less elegant than a single-pass solution.
The code is slightly more complex due to the need to manage the index for the result array manually.
Solutions
Solution
class Solution {public int[] decompressRLElist(int[] nums) { int n = 0; for (int i = 0; i < nums.length; i += 2) { n += nums[i]; } int[] res = new int[n]; for (int i = 1, k = 0; i < nums.length; i += 2) { for (int j = 0; j < nums[i - 1]; ++j) { res[k++] = nums[i]; } } return res; }}class Solution: def decompressRLElist(self, nums: List[int]) -> List[int]: res = [] for i in range(1, len(nums), 2): res . extend([nums[i]] * nums[i - 1]) return resclass Solution {public: vector<int> decompressRLElist(vector<int> &nums) { vector<int> res; for (int i = 1; i < nums.size(); i += 2) { for (int j = 0; j < nums[i - 1]; ++j) { res.push_back(nums[i]); } } return res; }};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.