Final Array State After K Multiplication Operations I
EasyPrompt
You are given an integer array nums, an integer k, and an integer multiplier.
You need to perform k operations on nums. In each operation:
- Find the minimum value
xinnums. If there are multiple occurrences of the minimum value, select the one that appears first. - Replace the selected minimum value
xwithx * multiplier.
Return an integer array denoting the final state of nums after performing all k operations.
Example 1:
Input: nums = [2,1,3,5,6], k = 5, multiplier = 2
Output: [8,4,6,5,6]
Explanation:
| Operation | Result |
|---|---|
| After operation 1 | [2, 2, 3, 5, 6] |
| After operation 2 | [4, 2, 3, 5, 6] |
| After operation 3 | [4, 4, 3, 5, 6] |
| After operation 4 | [4, 4, 6, 5, 6] |
| After operation 5 | [8, 4, 6, 5, 6] |
Example 2:
Input: nums = [1,2], k = 3, multiplier = 4
Output: [16,8]
Explanation:
| Operation | Result |
|---|---|
| After operation 1 | [4, 2] |
| After operation 2 | [4, 8] |
| After operation 3 | [16, 8] |
Constraints:
1 <= nums.length <= 1001 <= nums[i] <= 1001 <= k <= 101 <= multiplier <= 5
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. It iterates k times, and in each iteration, it scans the entire array to find the first occurrence of the minimum value and then updates it.
Algorithm
-
- Repeat the following process
ktimes.
- Repeat the following process
-
- Initialize
minIndexto -1 andminValueto a very large number (e.g.,Integer.MAX_VALUE).
- Initialize
-
- Iterate through the
numsarray from left to right (indexjfrom 0 ton-1).
- Iterate through the
-
- If the current element
nums[j]is less thanminValue, updateminValuetonums[j]andminIndextoj.
- If the current element
-
- After the inner loop completes,
minIndexwill hold the index of the first occurrence of the minimum value.
- After the inner loop completes,
-
- Update the array at the found index:
nums[minIndex] = nums[minIndex] * multiplier.
- Update the array at the found index:
-
- After the outer loop of
kiterations finishes, return the modifiednumsarray.
- After the outer loop of
Walkthrough
This method directly translates the problem statement into code. We loop k times to perform the k operations. In each operation, we iterate through the entire nums array to find the minimum value and its first index. The tie-breaking rule (selecting the one that appears first) is naturally handled by iterating from the beginning of the array and only updating the minimum index when a strictly smaller value is found. Once the target element is identified, we update its value by multiplying it with the multiplier. This process is repeated k times on the same array.
class Solution { public int[] getFinalArray(int[] nums, int k, int multiplier) { int n = nums.length; for (int i = 0; i < k; i++) { int minIndex = -1; int minValue = Integer.MAX_VALUE; // Find the first occurrence of the minimum value for (int j = 0; j < n; j++) { if (nums[j] < minValue) { minValue = nums[j]; minIndex = j; } } // Update the value at the found index if (minIndex != -1) { nums[minIndex] = nums[minIndex] * multiplier; } } return nums; }}Complexity
Time
O(k * n), where `n` is the number of elements in `nums`. For each of the `k` operations, we perform a linear scan of the array of size `n` to find the minimum element.
Space
O(1), as we are modifying the input array in-place and not using any extra space proportional to the input size.
Trade-offs
Pros
Simple to understand and implement.
Low memory overhead as it modifies the array in-place.
Cons
Inefficient for large inputs, as it requires scanning the entire array in each of the
koperations.
A more efficient approach uses a Min-Heap (Priority Queue) to quickly find the minimum element. To handle the tie-breaking rule (first occurrence), we store pairs of (value, index) in the heap.
Algorithm
-
- Create a Min-Heap (Priority Queue) that stores pairs of
(value, index).
- Create a Min-Heap (Priority Queue) that stores pairs of
-
- The heap's comparator should order elements first by
value(ascending) and then byindex(ascending) for tie-breaking.
- The heap's comparator should order elements first by
-
- Populate the heap by iterating through the input
numsarray and adding(nums[i], i)for each element.
- Populate the heap by iterating through the input
-
- Perform the multiplication operation
ktimes:
- a. Extract the minimum element
(value, index)from the heap usingpoll(). - b. Calculate the new value:
newValue = value * multiplier. - c. Insert the new pair
(newValue, index)back into the heap.
- Perform the multiplication operation
-
- After
koperations, create a new result array of the same size asnums.
- After
-
- Dequeue all elements from the heap and place each
valuein theresultarray at its correspondingindex.
- Dequeue all elements from the heap and place each
-
- Return the
resultarray.
- Return the
Walkthrough
To optimize the process of finding the minimum element in each step, we can use a Min-Heap, which is implemented as a PriorityQueue in Java. A standard heap on values alone isn't sufficient because we need to track the original index of each element to handle the tie-breaking rule and to reconstruct the final array.
Therefore, we store pairs of (value, index) in the priority queue. We define a custom comparator for the priority queue to first sort elements by their value in ascending order. If two elements have the same value, the comparator then sorts them by their index in ascending order. This ensures that if multiple elements have the same minimum value, the one with the smallest original index will be at the top of the heap.
The overall algorithm is as follows:
- Initialize and populate the priority queue with
(value, index)pairs from the inputnumsarray. - Loop
ktimes: extract the minimum element, calculate its new value, and insert the new(newValue, originalIndex)pair back into the queue. - After all operations, the priority queue contains the final state. We then create a result array and populate it by extracting all elements from the queue and placing them at their respective original indices.
import java.util.PriorityQueue; class Solution { public int[] getFinalArray(int[] nums, int k, int multiplier) { int n = nums.length; // PriorityQueue stores pairs of {value, index} // Comparator sorts by value, then by index for ties. PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> { if (a[0] != b[0]) { return a[0] - b[0]; // Compare by value } return a[1] - b[1]; // Compare by index for tie-breaking }); // Add all initial elements to the priority queue for (int i = 0; i < n; i++) { pq.add(new int[]{nums[i], i}); } // Perform k operations for (int i = 0; i < k; i++) { // Get the element with the minimum value int[] minElement = pq.poll(); int value = minElement[0]; int index = minElement[1]; // Calculate the new value int newValue = value * multiplier; // Add the updated element back to the queue pq.add(new int[]{newValue, index}); } // Reconstruct the final array from the priority queue int[] result = new int[n]; while (!pq.isEmpty()) { int[] e = pq.poll(); result[e[1]] = e[0]; } return result; }}Complexity
Time
O((n+k) log n). Building the heap by adding `n` elements takes O(n log n). Each of the `k` operations involves one extraction and one insertion, both taking O(log n), for a total of O(k log n). Reconstructing the final array takes another O(n log n).
Space
O(n), to store the `n` elements (as pairs of value and index) in the priority queue and for the result array.
Trade-offs
Pros
More efficient than the brute-force approach for larger inputs.
Finding the minimum element is a fast O(log n) operation.
Cons
Requires extra space for the heap.
Slightly more complex to implement due to the custom data structure (or pair) and comparator.
Solutions
Solution
class Solution {public int[] getFinalState(int[] nums, int k, int multiplier) { PriorityQueue<Integer> pq = new PriorityQueue<>( (i, j)->nums[i] - nums[j] == 0 ? i - j : nums[i] - nums[j]); for (int i = 0; i < nums.length; i++) { pq.offer(i); } while (k-- > 0) { int i = pq.poll(); nums[i] *= multiplier; pq.offer(i); } return nums; }}class Solution {public: vector<int> getFinalState(vector<int> &nums, int k, int multiplier) { auto cmp = [&nums](int i, int j) { return nums[i] == nums[j] ? i > j : nums[i] > nums[j]; }; priority_queue<int, vector<int>, decltype(cmp)> pq(cmp); for (int i = 0; i < nums.size(); ++i) { pq.push(i); } while (k--) { int i = pq.top(); pq.pop(); nums[i] *= multiplier; pq.push(i); } return nums; }};class Solution: def getFinalState(self, nums: List[int], k: int, multiplier: int) -> List[int]: pq = [(x, i) for i, x in enumerate(nums)] heapify(pq) for _ in range(k): _, i = heappop(pq) nums[i] *= multiplier heappush(pq, (nums[i], i)) return numsVideo 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.