📌  相关文章
📜  给定一个数组以及两个整数l和r,找到[l,r]范围内的第k个最大元素

📅  最后修改于: 2021-04-17 08:49:52             🧑  作者: Mango

给定n个整数和整数k的未排序数组arr [] ,任务是在给定的索引范围[l,r]中找到第k个最大元素

例子:

方法:一个简单的解决方案是将范围内的元素排序并获得第k个最大元素,该解决方案的时间复杂度将是每个查询的nlog(n) 。我们可以使用前缀数组和二进制搜索来解决log(n)中的每个查询。我们要做的就是维护一个2d前缀数组,其中第i行将包含与给定数组相同范围内小于等于i的元素数量。完成前缀数组后,我们需要做的就是对前缀数组进行简单的二进制搜索。因此,时间复杂度大大降低了。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
#define MAX 1001
static int prefix[MAX][MAX];
int ar[MAX];
  
// Function to calculate the prefix
void cal_prefix(int n, int arr[])
{
    int i, j;
  
    // Creating one based indexing
    for (i = 0; i < n; i++)
        ar[i + 1] = arr[i];
  
    // Initilizing and creating prefix array
    for (i = 1; i <= 1000; i++) {
        for (j = 0; j <= n; j++)
            prefix[i][j] = 0;
  
        for (j = 1; j <= n; j++) {
  
            // Creating a prefix array for every
            // possible value in a given range
            prefix[i][j] = prefix[i][j - 1]
                           + (int)(ar[j] <= i ? 1 : 0);
        }
    }
}
  
// Function to return the kth largest element
// in the index range [l, r]
int ksub(int l, int r, int n, int k)
{
    int lo, hi, mid;
  
    lo = 1;
    hi = 1000;
  
    // Binary searching through the 2d array
    // and only checking the range in which
    // the sub array is a part
    while (lo + 1 < hi) {
        mid = (lo + hi) / 2;
        if (prefix[mid][r] - prefix[mid][l - 1] >= k)
            hi = mid;
        else
            lo = mid + 1;
    }
  
    if (prefix[lo][r] - prefix[lo][l - 1] >= k)
        hi = lo;
  
    return hi;
}
  
// Driver code
int main()
{
    int arr[] = { 1, 4, 2, 3, 5, 7, 6 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 4;
  
    // Creating the prefix array
    // for the given array
    cal_prefix(n, arr);
  
    // Queries
    int queries[][3] = { { 1, n, 1 },
                         { 2, n - 2, 2 },
                         { 3, n - 1, 3 } };
    int q = sizeof(queries) / sizeof(queries[0]);
  
    // Perform queries
    for (int i = 0; i < q; i++)
        cout << ksub(queries[i][0], queries[i][1],
                     n, queries[i][2])
             << endl;
  
    return 0;
}


Java
// Java implementation of the approach
import java.util.*;
  
class GFG
{
      
static int MAX = 1001;
static int prefix[][] = new int[MAX][MAX];
static int ar[] = new int[MAX];
  
// Function to calculate the prefix
static void cal_prefix(int n, int arr[])
{
    int i, j;
  
    // Creating one based indexing
    for (i = 0; i < n; i++)
        ar[i + 1] = arr[i];
  
    // Initilizing and creating prefix array
    for (i = 1; i <= 1000; i++) 
    {
        for (j = 0; j <= n; j++)
            prefix[i][j] = 0;
  
        for (j = 1; j <= n; j++) 
        {
  
            // Creating a prefix array for every
            // possible value in a given range
            prefix[i][j] = prefix[i][j - 1]
                        + (int)(ar[j] <= i ? 1 : 0);
        }
    }
}
  
// Function to return the kth largest element
// in the index range [l, r]
static int ksub(int l, int r, int n, int k)
{
    int lo, hi, mid;
  
    lo = 1;
    hi = 1000;
  
    // Binary searching through the 2d array
    // and only checking the range in which
    // the sub array is a part
    while (lo + 1 < hi) 
    {
        mid = (lo + hi) / 2;
        if (prefix[mid][r] - prefix[mid][l - 1] >= k)
            hi = mid;
        else
            lo = mid + 1;
    }
  
    if (prefix[lo][r] - prefix[lo][l - 1] >= k)
        hi = lo;
  
    return hi;
}
  
// Driver code
public static void main(String args[])
{
    int arr[] = { 1, 4, 2, 3, 5, 7, 6 };
    int n = arr.length;
    int k = 4;
  
    // Creating the prefix array
    // for the given array
    cal_prefix(n, arr);
  
    // Queries
    int queries[][] = { { 1, n, 1 },
                        { 2, n - 2, 2 },
                        { 3, n - 1, 3 } };
    int q = queries.length;
  
    // Perform queries
    for (int i = 0; i < q; i++)
        System.out.println( ksub(queries[i][0], queries[i][1],
                    n, queries[i][2]));
}
}
  
// This code is contributed by Arnab Kundu


Python3
# Python3 implementation of the approach
  
MAX = 1001
prefix = [[0 for i in range(MAX)] 
             for j in range(MAX)]
ar = [0 for i in range(MAX)]
  
# Function to calculate the prefix
def cal_prefix(n, arr):
      
    # Creating one based indexing
    for i in range(n):
        ar[i + 1] = arr[i]
  
    # Initilizing and creating prefix array
    for i in range(1, 1001, 1):
        for j in range(n + 1):
            prefix[i][j] = 0
  
        for j in range(1, n + 1):
              
            # Creating a prefix array for every
            # possible value in a given range
            if ar[j] <= i:
                k = 1
            else:
                k = 0
            prefix[i][j] = prefix[i][j - 1] + k
  
# Function to return the kth largest element
# in the index range [l, r]
def ksub(l, r, n, k):
    lo = 1
    hi = 1000
  
    # Binary searching through the 2d array
    # and only checking the range in which
    # the sub array is a part
    while (lo + 1 < hi):
        mid = int((lo + hi) / 2)
        if (prefix[mid][r] - 
            prefix[mid][l - 1] >= k):
            hi = mid
        else:
            lo = mid + 1
  
    if (prefix[lo][r] - 
        prefix[lo][l - 1] >= k):
        hi = lo
  
    return hi
  
# Driver code
if __name__ == '__main__':
    arr = [1, 4, 2, 3, 5, 7, 6]
    n = len(arr)
    k = 4
  
    # Creating the prefix array
    # for the given array
    cal_prefix(n, arr)
  
    # Queries
    queries = [[1, n, 1],
               [2, n - 2, 2],
               [3, n - 1, 3]]
    q = len(queries)
  
    # Perform queries
    for i in range(q):
        print(ksub(queries[i][0], 
                   queries[i][1], n, queries[i][2]))
          
# This code is contributed by
# Surendra_Gangwar


C#
// C# implementation of the approach
using System;
  
class GFG
{
      
static int MAX = 1001;
static int[,] prefix = new int[MAX,MAX];
static int[] ar = new int[MAX];
  
// Function to calculate the prefix
static void cal_prefix(int n, int[] arr)
{
    int i, j;
  
    // Creating one based indexing
    for (i = 0; i < n; i++)
        ar[i + 1] = arr[i];
  
    // Initilizing and creating prefix array
    for (i = 1; i <= 1000; i++) 
    {
        for (j = 0; j <= n; j++)
            prefix[i, j] = 0;
  
        for (j = 1; j <= n; j++) 
        {
  
            // Creating a prefix array for every
            // possible value in a given range
            prefix[i, j] = prefix[i, j - 1]
                        + (int)(ar[j] <= i ? 1 : 0);
        }
    }
}
  
// Function to return the kth largest element
// in the index range [l, r]
static int ksub(int l, int r, int n, int k)
{
    int lo, hi, mid;
  
    lo = 1;
    hi = 1000;
  
    // Binary searching through the 2d array
    // and only checking the range in which
    // the sub array is a part
    while (lo + 1 < hi) 
    {
        mid = (lo + hi) / 2;
        if (prefix[mid, r] - prefix[mid, l - 1] >= k)
            hi = mid;
        else
            lo = mid + 1;
    }
  
    if (prefix[lo, r] - prefix[lo, l - 1] >= k)
        hi = lo;
  
    return hi;
}
  
// Driver code
static void Main()
{
    int []arr = { 1, 4, 2, 3, 5, 7, 6 };
    int n = arr.Length;
    //int k = 4;
  
    // Creating the prefix array
    // for the given array
    cal_prefix(n, arr);
  
    // Queries
    int [,]queries = { { 1, n, 1 },
                        { 2, n - 2, 2 },
                        { 3, n - 1, 3 } };
    int q = queries.Length/queries.Rank-1;
  
    // Perform queries
    for (int i = 0; i < q; i++)
        Console.WriteLine( ksub(queries[i,0], queries[i,1],
                    n, queries[i, 2]));
}
}
  
// This code is contributed by mits


PHP
= $k)
            $hi = $mid;
        else
            $lo = $mid + 1;
    }
  
    if ($prefix[$lo][$r] - $prefix[$lo][$l - 1] >= $k)
        $hi = $lo;
  
    return $hi;
}
  
    // Driver code
    $arr = array( 1, 4, 2, 3, 5, 7, 6 );
    $n = count($arr);
    $k = 4;
  
    // Creating the prefix array
    // for the given array
    cal_prefix($n, $arr);
  
    // Queries
    $queries = array(array( 1, $n, 1 ),
                        array( 2, $n - 2, 2 ),
                        array( 3, $n - 1, 3 ));
    $q = count($queries);
  
    // Perform queries
    for ($i = 0; $i < $q; $i++)
        echo ksub($queries[$i][0], $queries[$i][1],$n, $queries[$i][2])."\n";
  
    // This code is contributed by mits
?>


输出:
1
3
5