Given an array of integers arr
and an integer k
, you are to find the k
strongest values in the array according to the following definition of strength:
m
of the array arr
. If the array has an odd length, m
is the middle element after sorting. If even, m
is the element at index (n-1)//2
after sorting, where n
is the array's length.x
is defined as |x - m|
. If two values have the same strength, the larger value is considered stronger.k
strongest values, in any order.Constraints:
At first glance, it may seem like we need to compute the strength for every element and then pick the top k
strongest. A brute-force approach would be to:
k
elements.However, since sorting and recomputing strengths could be expensive for large arrays, we look for optimizations. Notably, since strength depends on the median, and sorting is required for finding the median anyway, we can reuse this sorted order to efficiently select the strongest values.
Using two pointers (one from each end of the sorted array), we can always pick the stronger of the two candidates at each step. This leverages the fact that values farthest from the median are at the ends of the sorted array.
n
, the median is at index (n-1)//2
in the sorted array.
left
at the start and right
at the end of the array. At each step:
arr[left]
and arr[right]
(i.e., |arr[left] - m|
vs |arr[right] - m|
).arr[right]
and decrement right
.arr[left]
and increment left
.k
elements are picked.k
strongest, as defined.
This approach is efficient because it avoids sorting the entire array by strength, and instead picks strongest values directly using the sorted order.
Let's walk through an example with arr = [1, 2, 3, 4, 5]
and k = 2
.
[1, 2, 3, 4, 5]
(5-1)//2 = 2
.m = 3
.
arr[0] = 1
), right = 4 (arr[4] = 5
)arr[3] = 4
)[5, 1]
(order doesn't matter)
The key insight is that, after sorting, the strongest elements (those farthest from the median) are at the ends of the array. By using two pointers, we can efficiently select the k
strongest values without the need for an additional sort by strength. This makes the solution both elegant and efficient, with time complexity dominated by the initial sort.
class Solution:
def getStrongest(self, arr, k):
arr.sort()
n = len(arr)
median = arr[(n - 1) // 2]
left, right = 0, n - 1
result = []
while k > 0:
if abs(arr[right] - median) >= abs(arr[left] - median):
result.append(arr[right])
right -= 1
else:
result.append(arr[left])
left += 1
k -= 1
return result
class Solution {
public:
vector<int> getStrongest(vector<int>& arr, int k) {
sort(arr.begin(), arr.end());
int n = arr.size();
int median = arr[(n - 1) / 2];
int left = 0, right = n - 1;
vector<int> result;
while (k-- > 0) {
if (abs(arr[right] - median) >= abs(arr[left] - median)) {
result.push_back(arr[right--]);
} else {
result.push_back(arr[left++]);
}
}
return result;
}
};
import java.util.*;
class Solution {
public int[] getStrongest(int[] arr, int k) {
Arrays.sort(arr);
int n = arr.length;
int median = arr[(n - 1) / 2];
int left = 0, right = n - 1;
int[] result = new int[k];
int idx = 0;
while (k-- > 0) {
if (Math.abs(arr[right] - median) >= Math.abs(arr[left] - median)) {
result[idx++] = arr[right--];
} else {
result[idx++] = arr[left++];
}
}
return result;
}
}
var getStrongest = function(arr, k) {
arr.sort((a, b) => a - b);
let n = arr.length;
let median = arr[Math.floor((n - 1) / 2)];
let left = 0, right = n - 1;
let result = [];
while (k-- > 0) {
if (Math.abs(arr[right] - median) >= Math.abs(arr[left] - median)) {
result.push(arr[right--]);
} else {
result.push(arr[left++]);
}
}
return result;
};