Minimum Operations to Make Median of Array Equal to K
MedPrompt
You are given an integer array nums and a non-negative integer k. In one operation, you can increase or decrease any element by 1.
Return the minimum number of operations needed to make the median of nums equal to k.
The median of an array is defined as the middle element of the array when it is sorted in non-decreasing order. If there are two choices for a median, the larger of the two values is taken.
Example 1:
Input: nums = [2,5,6,8,5], k = 4
Output: 2
Explanation:
We can subtract one from nums[1] and nums[4] to obtain [2, 4, 6, 8, 4]. The median of the resulting array is equal to k.
Example 2:
Input: nums = [2,5,6,8,5], k = 7
Output: 3
Explanation:
We can add one to nums[1] twice and add one to nums[2] once to obtain [2, 7, 7, 8, 5].
Example 3:
Input: nums = [1,2,3,4,5,6], k = 4
Output: 0
Explanation:
The median of the array is already equal to k.
Constraints:
1 <= nums.length <= 2 * 1051 <= nums[i] <= 1091 <= k <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
A straightforward approach is to first sort the array. Once sorted, the median is at a fixed position. We can then calculate the minimum operations by iterating through the relevant half of the array and summing up the differences needed to make elements satisfy the median condition with respect to k.
Algorithm
- Sort the input array
numsin non-decreasing order. - Determine the size of the array,
n, and find the median index,m = n / 2. - Initialize a
longvariableoperationsto0to accumulate the total cost. - If the element at the median index,
nums[m], is greater thank:- Iterate from the beginning of the array up to the median index (
ifrom0tom). - For each element
nums[i]that is greater thank, add the differencenums[i] - ktooperations.
- Iterate from the beginning of the array up to the median index (
- If
nums[m]is less thank:- Iterate from the median index to the end of the array (
ifrommton-1). - For each element
nums[i]that is less thank, add the differencek - nums[i]tooperations.
- Iterate from the median index to the end of the array (
- If
nums[m]is equal tok, no operations are needed, and the loops will correctly result in0operations. - Return the total
operations.
Walkthrough
The core idea is that to change the median to k, we only need to modify one half of the array.
First, sort the input array nums. The median is the element at index m = n / 2 (0-indexed), where n is the length of the array. This is because the problem defines the median as the larger of the two middle elements for even-sized arrays, which corresponds to the element at index n/2.
- If the current median
nums[m]is already equal tok, no operations are needed. - If
nums[m]is less thank, we need to increase the median. To do this with minimum operations, we must increasenums[m]and any subsequent elements that are also less thank. We iterate from the median indexmto the end of the array. For each elementnums[i] < k, we addk - nums[i]to our total operations count. This ensures that at least half of the elements arekor greater, makingkthe new median. - If
nums[m]is greater thank, we need to decrease the median. Symmetrically, we must decreasenums[m]and any preceding elements that are greater thank. We iterate from the median indexmdown to the beginning. For each elementnums[i] > k, we addnums[i] - kto the total operations. This ensures at least half of the elements arekor smaller.
The total sum of these adjustments gives the minimum number of operations. A long should be used for the operations count to prevent potential overflow.
import java.util.Arrays; class Solution { public long minOperationsToMakeMedianK(int[] nums, int k) { Arrays.sort(nums); long operations = 0; int n = nums.length; int medianIndex = n / 2; if (nums[medianIndex] > k) { // Decrease elements in the lower half (including median) that are > k for (int i = medianIndex; i >= 0; i--) { if (nums[i] > k) { operations += (long)nums[i] - k; } else { break; // Array is sorted, no more elements will be > k } } } else if (nums[medianIndex] < k) { // Increase elements in the upper half (including median) that are < k for (int i = medianIndex; i < n; i++) { if (nums[i] < k) { operations += (long)k - nums[i]; } else { break; // Array is sorted, no more elements will be < k } } } return operations; }}Complexity
Time
O(N log N)
Space
O(log N) or O(N)
Trade-offs
Pros
Simple to understand and implement.
Leverages standard, well-tested library functions for sorting.
Cons
The time complexity of O(N log N) is not optimal for this problem, as a linear time solution exists.
A more optimal approach avoids the O(N log N) cost of a full sort. By using a selection algorithm like Quickselect, we can find the median element and partition the array in O(N) time on average. After partitioning, the elements are arranged such that the median is in its correct sorted position. We can then apply the same logic as the sorting approach to calculate the operations on the partially sorted array.
Algorithm
- Find the median index
m = nums.length / 2. - Use a selection algorithm (like Quickselect) to partition the array
numsaround them-th element. After this operation,nums[m]holds the true median value, all elements at indices< mare less than or equal tonums[m], and all elements at indices> mare greater than or equal tonums[m]. - Initialize
operations = 0L. - If
nums[m] > k, iterate fromi = 0tom. For eachnums[i] > k, addnums[i] - ktooperations. - If
nums[m] < k, iterate fromi = mton-1. For eachnums[i] < k, addk - nums[i]tooperations. - Return
operations.
Walkthrough
This approach improves upon the first one by replacing the full sort with a faster selection algorithm. The goal is to find the median element and partition the array around it without sorting the entire array.
An algorithm like Quickselect can find the k-th smallest element in an array in average linear time, O(N). We use it to find the element that would be at the median index m = n / 2.
This operation rearranges the array nums such that nums[m] holds the true median value, all elements at indices less than m are less than or equal to nums[m], and all elements at indices greater than m are greater than or equal to nums[m]. Once the array is partitioned this way, the logic is identical to the sorting-based approach:
- If
nums[m] < k, we iterate through the second half of the (now partitioned) array (from indexmton-1) and sum the costsk - nums[i]for anynums[i] < k. - If
nums[m] > k, we iterate through the first half (from indexmdown to0) and sum the costsnums[i] - kfor anynums[i] > k.
This method achieves a better time complexity, which can be significant for very large inputs. While Java's standard library does not provide a direct nth_element function, implementing Quickselect is a common way to achieve this linear time performance.
import java.util.concurrent.ThreadLocalRandom; class Solution { public long minOperationsToMakeMedianK(int[] nums, int k) { int n = nums.length; int medianIndex = n / 2; // Partition the array using Quickselect to find the median element quickSelect(nums, 0, n - 1, medianIndex); long operations = 0; int medianValue = nums[medianIndex]; if (medianValue > k) { for (int i = 0; i <= medianIndex; i++) { if (nums[i] > k) { operations += (long)nums[i] - k; } } } else if (medianValue < k) { for (int i = medianIndex; i < n; i++) { if (nums[i] < k) { operations += (long)k - nums[i]; } } } return operations; } // Iterative Quickselect to find the k-th smallest element private void quickSelect(int[] nums, int left, int right, int k) { while (left < right) { int pivotIndex = partition(nums, left, right); if (pivotIndex == k) { return; } else if (pivotIndex < k) { left = pivotIndex + 1; } else { right = pivotIndex - 1; } } } private int partition(int[] nums, int left, int right) { int pivotIndex = ThreadLocalRandom.current().nextInt(left, right + 1); int pivotValue = nums[pivotIndex]; swap(nums, pivotIndex, right); int storeIndex = left; for (int i = left; i < right; i++) { if (nums[i] < pivotValue) { swap(nums, storeIndex, i); storeIndex++; } } swap(nums, right, storeIndex); return storeIndex; } private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }}Complexity
Time
O(N) on average
Space
O(log N)
Trade-offs
Pros
Asymptotically faster with O(N) average time complexity.
More efficient for very large datasets where the log N factor from sorting would be significant.
Cons
More complex to implement correctly compared to sorting.
A naive Quickselect has a worst-case time complexity of O(N^2), though this is rare with good pivot selection. A guaranteed O(N) version (e.g., Introselect) is even more complex.
Solutions
Solution
class Solution {public long minOperationsToMakeMedianK(int[] nums, int k) { Arrays.sort(nums); int n = nums.length; int m = n >> 1; long ans = Math.abs(nums[m] - k); if (nums[m] > k) { for (int i = m - 1; i >= 0 && nums[i] > k; --i) { ans += nums[i] - k; } } else { for (int i = m + 1; i < n && nums[i] < k; ++i) { ans += k - nums[i]; } } return ans; }}class Solution {public: long long minOperationsToMakeMedianK(vector<int> &nums, int k) { sort(nums.begin(), nums.end()); int n = nums.size(); int m = n >> 1; long long ans = abs(nums[m] - k); if (nums[m] > k) { for (int i = m - 1; i >= 0 && nums[i] > k; --i) { ans += nums[i] - k; } } else { for (int i = m + 1; i < n && nums[i] < k; ++i) { ans += k - nums[i]; } } return ans; }};class Solution: def minOperationsToMakeMedianK(self, nums: List[int], k: int) -> int: nums . sort() n = len(nums) m = n >> 1 ans = abs(nums[m] - k) if nums[m] > k: for i in range(m - 1, - 1, - 1): if nums[i] <= k: break ans += nums[i] - k else: for i in range(m + 1, n): if nums[i] >= k: break ans += k - nums[i] return ansVideo 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.