📌  相关文章
📜  使用细分树的所有大小为K的子数组的最大值

📅  最后修改于: 2021-05-19 18:14:58             🧑  作者: Mango

给定一个数组arr []和一个整数K ,任务是为大小为K的每个连续子数组找到最大值。

例子:

方法
这个想法是使用细分树来回答大小为K的所有子数组的最大值。

  1. 段树的表示
    • 叶节点是输入数组的元素。
    • 每个内部节点代表其所有子节点的最大值。
  2. 从给定数组构造细分树:
    • 我们从一个段arr [0开始。 。 。 [n-1],并且每次我们将当前段分成两半(如果尚未变成长度为1的段),然后在这两个半段上调用相同的过程,则对于每个这样的段,我们都会存储最大值段树节点中的值。
    • 除最后一个级别外,已构建的段树的所有级别都将被完全填充。而且,该树将是完整的二叉树,因为我们总是在每个级别将分段分为两半。
    • 由于构造的树始终是具有n个叶的完整二叉树,因此将存在n – 1个内部节点。因此,总节点数将为2 * n – 1。
    • 段树的高度将为log 2 n
    • 由于树是使用数组表示的,并且必须保持父索引和子索引之间的关系,因此为段树分配的内存大小将为2 *(2 ceil(log 2 n) )-1

下面是上述方法的实现。

C++
// C++  program to answer Maximum
// of allsubarrays of size k
// using segment tree
#include 
using namespace std;
 
#define MAX 1000000
 
// Size of segment
// tree = 2^{log(MAX)+1}
int st[3 * MAX];
 
// A utility function to get the
// middle index of given range.
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
// A recursive function that
// constructs Segment Tree for
// array[s...e]. node is index
// of current node in segment
// tree st
void constructST(int node, int s,
                 int e, int arr[])
{
    // If there is one element in
    // array, store it in current
    // node of segment tree and return
    if (s == e) {
        st[node] = arr[s];
        return;
    }
    // If there are more than
    // one elements, then recur
    // for left and right subtrees
    // and store the max of
    // values in this node
    int mid = getMid(s, e);
 
    constructST(2 * node, s,
                mid, arr);
    constructST(2 * node + 1,
                mid + 1, e,
                arr);
    st[node] = max(st[2 * node],
                   st[2 * node + 1]);
}
 
/* A recursive function to get the
   maximum of range[l, r] The
   following paramaters for
   this function:
 
st     -> Pointer to segment tree
node   -> Index of current node in
          the segment tree .
s & e  -> Starting and ending indexes
          of the segment represented
          by current node, i.e., st[node]
l & r  -> Starting and ending indexes
          of range query
 */
int getMax(int node, int s,
           int e, int l,
           int r)
{
    // If segment of this node
    // does not belong to
    // given range
    if (s > r || e < l)
        return INT_MIN;
 
    // If segment of this node
    // is completely part of
    // given range, then return
    // the max of segment
    if (s >= l && e <= r)
        return st[node];
 
    // If segment of this node
    // is partially the part
    // of given range
    int mid = getMid(s, e);
 
    return max(getMax(2 * node,
                      s, mid,
                      l, r),
               getMax(2 * node + 1,
                      mid + 1, e,
                      l, r));
}
 
// Function to print the max
// of all subarrays of size k
void printKMax(int n, int k)
{
    for (int i = 0; i < n; i++) {
        if ((k - 1 + i) < n)
            cout << getMax(1, 0, n - 1,
                           i, k - 1 + i)
                 << " ";
        else
            break;
    }
}
 
// Driver code
int main()
{
    int k = 4;
    int arr[] = { 8, 5, 10, 7, 9, 4, 15,
                  12, 90, 13 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Function to construct the
    // segment tree
    constructST(1, 0, n - 1, arr);
 
    printKMax(n, k);
 
    return 0;
}


Java
// Java program to answer Maximum
// of allsubarrays of size k
// using segment tree
import java.io.*;
import java.util.*;
 
class GFG{
 
static int MAX = 1000000;
 
// Size of segment
// tree = 2^{log(MAX)+1}
static int[] st = new int[3 * MAX];
 
// A utility function to get the
// middle index of given range.
static int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// A recursive function that
// constructs Segment Tree for
// array[s...e]. node is index
// of current node in segment
// tree st
static void constructST(int node, int s,
                        int e, int[] arr)
{
     
    // If there is one element in
    // array, store it in current
    // node of segment tree and return
    if (s == e)
    {
        st[node] = arr[s];
        return;
    }
     
    // If there are more than
    // one elements, then recur
    // for left and right subtrees
    // and store the max of
    // values in this node
    int mid = getMid(s, e);
 
    constructST(2 * node, s, mid, arr);
    constructST(2 * node + 1,
                mid + 1, e, arr);
     
    st[node] = Math.max(st[2 * node],
                        st[2 * node + 1]);
}
 
/* A recursive function to get the
   maximum of range[l, r] The
   following paramaters for
   this function:
 
st     -> Pointer to segment tree
node   -> Index of current node in
          the segment tree .
s & e  -> Starting and ending indexes
          of the segment represented
          by current node, i.e., st[node]
l & r  -> Starting and ending indexes
          of range query
 */
static int getMax(int node, int s, int e,
                            int l, int r)
{
     
    // If segment of this node
    // does not belong to
    // given range
    if (s > r || e < l)
        return Integer.MIN_VALUE;
 
    // If segment of this node
    // is completely part of
    // given range, then return
    // the max of segment
    if (s >= l && e <= r)
        return st[node];
 
    // If segment of this node
    // is partially the part
    // of given range
    int mid = getMid(s, e);
 
    return Math.max(getMax(2 * node, s,
                           mid, l, r),
                    getMax(2 * node + 1,
                           mid + 1, e, l, r));
}
 
// Function to print the max
// of all subarrays of size k
static void printKMax(int n, int k)
{
    for(int i = 0; i < n; i++)
    {
        if ((k - 1 + i) < n)
            System.out.print(getMax(1, 0, n - 1,
                                    i, k - 1 + i) + " ");
        else
            break;
    }
}
 
// Driver code
public static void main(String[] args)
{
    int k = 4;
    int[] arr = { 8, 5, 10, 7, 9,
                  4, 15, 12, 90, 13 };
    int n = arr.length;
 
    // Function to construct the
    // segment tree
    constructST(1, 0, n - 1, arr);
 
    printKMax(n, k);
}
}
 
// This code is contributed by akhilsaini


Python3
# Python3 program to answer maximum
# of all subarrays of size k
# using segment tree
import sys
 
MAX = 1000000
 
# Size of segment
# tree = 2^{log(MAX)+1}
st = [0] * (3 * MAX)
 
# A utility function to get the
# middle index of given range.
def getMid(s, e):
    return s + (e - s) // 2
     
# A recursive function that
# constructs Segment Tree for
# array[s...e]. node is index
# of current node in segment
# tree st
def constructST(node, s, e, arr):
 
    # If there is one element in
    # array, store it in current
    # node of segment tree and return
    if (s == e):
        st[node] = arr[s]
        return
 
    # If there are more than
    # one elements, then recur
    # for left and right subtrees
    # and store the max of
    # values in this node
    mid = getMid(s, e)
    constructST(2 * node, s, mid, arr)
    constructST(2 * node + 1, mid + 1, e, arr)
    st[node] = max(st[2 * node], st[2 * node + 1])
 
''' A recursive function to get the
maximum of range[l, r] The
following paramaters for
this function:
 
st     -> Pointer to segment tree
node -> Index of current node in
        the segment tree .
s & e -> Starting and ending indexes
        of the segment represented
        by current node, i.e., st[node]
l & r -> Starting and ending indexes
        of range query
'''
def getMax(node, s, e, l, r):
 
    # If segment of this node
    # does not belong to
    # given range
    if (s > r or e < l):
        return (-sys.maxsize - 1)
 
    # If segment of this node
    # is completely part of
    # given range, then return
    # the max of segment
    if (s >= l and e <= r):
        return st[node]
 
    # If segment of this node
    # is partially the part
    # of given range
    mid = getMid(s, e)
 
    return max(getMax(2 * node, s, mid, l, r),
               getMax(2 * node + 1, mid + 1, e, l, r))
 
# Function to print the max
# of all subarrays of size k
def printKMax(n, k):
 
    for i in range(n):
        if ((k - 1 + i) < n):
            print(getMax(1, 0, n - 1, i,
                               k - 1 + i), end = " ")
        else:
            break
 
# Driver code
if __name__ == "__main__":
     
    k = 4
    arr = [ 8, 5, 10, 7, 9, 4, 15, 12, 90, 13 ]
    n = len(arr)
 
    # Function to construct the
    # segment tree
    constructST(1, 0, n - 1, arr)
     
    printKMax(n, k)
 
# This code is contributed by chitranayal


C#
// C# program to answer Maximum
// of allsubarrays of size k
// using segment tree
using System;
 
class GFG{
 
static int MAX = 1000000;
 
// Size of segment
// tree = 2^{log(MAX)+1}
static int[] st = new int[3 * MAX];
 
// A utility function to get the
// middle index of given range.
static int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// A recursive function that
// constructs Segment Tree for
// array[s...e]. node is index
// of current node in segment
// tree st
static void constructST(int node, int s,
                        int e, int[] arr)
{
     
    // If there is one element in
    // array, store it in current
    // node of segment tree and return
    if (s == e)
    {
        st[node] = arr[s];
        return;
    }
     
    // If there are more than
    // one elements, then recur
    // for left and right subtrees
    // and store the max of
    // values in this node
    int mid = getMid(s, e);
 
    constructST(2 * node, s, mid, arr);
    constructST(2 * node + 1, mid + 1, e, arr);
     
    st[node] = Math.Max(st[2 * node],
                        st[2 * node + 1]);
}
 
/* A recursive function to get the
   maximum of range[l, r] The
   following paramaters for
   this function:
 
st     -> Pointer to segment tree
node   -> Index of current node in
          the segment tree .
s & e  -> Starting and ending indexes
          of the segment represented
          by current node, i.e., st[node]
l & r  -> Starting and ending indexes
          of range query
 */
static int getMax(int node, int s, int e,
                            int l, int r)
{
     
    // If segment of this node
    // does not belong to
    // given range
    if (s > r || e < l)
        return int.MinValue;
 
    // If segment of this node
    // is completely part of
    // given range, then return
    // the max of segment
    if (s >= l && e <= r)
        return st[node];
 
    // If segment of this node
    // is partially the part
    // of given range
    int mid = getMid(s, e);
 
    return Math.Max(getMax(2 * node, s,
                           mid, l, r),
                    getMax(2 * node + 1,
                           mid + 1, e, l, r));
}
 
// Function to print the max
// of all subarrays of size k
static void printKMax(int n, int k)
{
    for(int i = 0; i < n; i++)
    {
        if ((k - 1 + i) < n)
            Console.Write(getMax(1, 0, n - 1,
                                 i, k - 1 + i) + " ");
        else
            break;
    }
}
 
// Driver code
public static void Main()
{
    int k = 4;
    int[] arr = { 8, 5, 10, 7, 9,
                  4, 15, 12, 90, 13 };
    int n = arr.Length;
 
    // Function to construct the
    // segment tree
    constructST(1, 0, n - 1, arr);
 
    printKMax(n, k);
}
}
 
// This code is contributed by akhilsaini


输出:
10 10 10 15 15 90 90


时间复杂度: O(N * log K)
相关文章:最大滑动窗口(大小为k的所有子数组的最大值)