给定一个整数arr[]和一个整数k的数组,任务是找到每个大小为k 的窗口的中值,从左侧开始,每次向右移动一个位置。
例子:
Input: arr[] = {-1, 5, 13, 8, 2, 3, 3, 1}, k = 3
Output: 5 8 8 3 3 3
Input: arr[] = {-1, 5, 13, 8, 2, 3, 3, 1}, k = 4
Output: 6.5 6.5 5.5 3.0 2.5
方法:创建一个配对类来保存项目及其索引。它还实现了可比较的接口,以便 Treeset 调用 compareTo() 方法来查找节点。请注意,只有当它们的索引相等时,这两个对才相等。这很重要,因为窗口可能包含重复项,如果我们只检查值,我们可能最终会在单个 remove() 调用中删除多个项目。
这个想法是根据k是偶数还是奇数来维护长度为 (k / 2)和(k / 2) + 1的 Pair 对象的两个排序集(minSet 和 maxSet),minSet 将始终包含第一组数字(较小)的窗口k和 maxSet 将包含第二组数字(较大)。
当我们移动窗口时,我们将从任何一个集合 (log n) 中删除元素并添加一个新元素 (log n),保持上面指定的 minSet 和 maxSet 规则。
下面是上述方法的实现:
// Java implementation of the approach
import java.util.TreeSet;
public class GFG {
// Pair class for the value and its index
static class Pair implements Comparable {
private int value, index;
// Constructor
public Pair(int v, int p)
{
value = v;
index = p;
}
// This method will be used by the treeset to
// search a value by index and setting the tree
// nodes (left or right)
@Override
public int compareTo(Pair o)
{
// Two nodes are equal only when
// their indices are same
if (index == o.index) {
return 0;
}
else if (value == o.value) {
return Integer.compare(index, o.index);
}
else {
return Integer.compare(value, o.value);
}
}
// Function to return the value
// of the current object
public int value()
{
return value;
}
// Update the value and the position
// for the same object to save space
public void renew(int v, int p)
{
value = v;
index = p;
}
@Override
public String toString()
{
return String.format("(%d, %d)", value, index);
}
}
// Function to print the median for the current window
static void printMedian(TreeSet minSet,
TreeSet maxSet, int window)
{
// If the window size is even then the
// median will be the average of the
// two middle elements
if (window % 2 == 0) {
System.out.print((minSet.last().value()
+ maxSet.first().value())
/ 2.0);
System.out.print(" ");
}
// Else it will be the middle element
else {
System.out.print(minSet.size() > maxSet.size()
? minSet.last().value()
: maxSet.first().value());
System.out.print(" ");
}
}
// Function to find the median
// of every window of size k
static void findMedian(int arr[], int k)
{
TreeSet minSet = new TreeSet<>();
TreeSet maxSet = new TreeSet<>();
// To hold the pairs, we will keep renewing
// these instead of creating the new pairs
Pair[] windowPairs = new Pair[k];
for (int i = 0; i < k; i++) {
windowPairs[i] = new Pair(arr[i], i);
}
// Add k/2 items to maxSet
for (int i = 0; i < k / 2; i++) {
maxSet.add(windowPairs[i]);
}
for (int i = k / 2; i < k; i++) {
// Below logic is to maintain the
// maxSet and the minSet criteria
if (arr[i] < maxSet.first().value()) {
minSet.add(windowPairs[i]);
}
else {
minSet.add(maxSet.pollFirst());
maxSet.add(windowPairs[i]);
}
}
printMedian(minSet, maxSet, k);
for (int i = k; i < arr.length; i++) {
// Get the pair at the start of the window, this
// will reset to 0 at every k, 2k, 3k, ...
Pair temp = windowPairs[i % k];
if (temp.value() <= minSet.last().value()) {
// Remove the starting pair of the window
minSet.remove(temp);
// Renew window start to new window end
temp.renew(arr[i], i);
// Below logic is to maintain the
// maxSet and the minSet criteria
if (temp.value() < maxSet.first().value()) {
minSet.add(temp);
}
else {
minSet.add(maxSet.pollFirst());
maxSet.add(temp);
}
}
else {
maxSet.remove(temp);
temp.renew(arr[i], i);
// Below logic is to maintain the
// maxSet and the minSet criteria
if (temp.value() > minSet.last().value()) {
maxSet.add(temp);
}
else {
maxSet.add(minSet.pollLast());
minSet.add(temp);
}
}
printMedian(minSet, maxSet, k);
}
}
// Driver code
public static void main(String[] args)
{
int[] arr = new int[] { 0, 9, 1, 8, 2,
7, 3, 6, 4, 5 };
int k = 3;
findMedian(arr, k);
}
}
输出:
1 8 2 7 3 6 4 5
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。