给定前N 个自然数的排列P ,任务是计算索引对(i, j)使得P[i] + P[j] = max(P[x])其中i ≤ x ≤ j 。
例子:
Input: P[] = {3, 4, 1, 5, 2}
Output: 2
Only valid index pairs are (0, 4) and (0, 2)
Input: P[] = {1, 3, 2}
Output: 1
朴素的方法:我们可以通过迭代所有可能的对(i, j)来解决这个问题,并且每次在它们之间获得最大值。这种方法的时间复杂度为O(n 3 ) 。
有效的方法:固定一个段上的最大元素,并对其左侧或右侧的元素进行迭代。如果当前最大值是x,我们找到的元素是y,那么检查元素xy是否可以和y形成一个子段(即x是y和xy之间的段上的最大值)。这适用于 O(n*n)
但是如果我们可以预先计算段的边界,其中 x 是最大元素,并且总是选择对段的较小部分进行迭代,那么时间复杂度将降低到 O(nlogn)。
因为每个元素都会被处理不超过 logn 次,如果我们在一个大小为 m 的段中处理它,它的较小部分包含不超过 m/2 个元素(我们稍后会处理,而这个段的较小部分包含包含不超过 m/4 个元素,依此类推..)。
下面是上述方法的实现:
C++
// CPP implementation of the approach
#include
using namespace std;
// Function to return the count of
// required index pairs
int Count_Segment(int p[], int n)
{
// To store the required count
int count = 0;
// Array to store the left elements
// upto which current element is maximum
int upto[n + 1];
for(int i = 0; i < n + 1; i++)
upto[i] = 0;
// Iterating through the whole permutation
// except first and last element
int j = 0,curr = 0;
for (int i = 1; i < n + 1; i++)
{
// If current element can be maximum
// in a subsegment
if (p[i] > p[i - 1] and p[i] > p[i + 1])
{
// Current maximum
curr = p[i];
// Iterating for smaller values then
// current maximum on left of it
j = i - 1;
while (j >= 0 and p[j] < curr)
{
// Storing left borders
// of the current maximum
upto[p[j]]= curr;
j -= 1;
}
// Iterating for smaller values then
// current maximum on right of it
j = i + 1;
while (j < n and p[j] < curr)
{
// Condition satisfies
if (upto[curr-p[j]] == curr)
count += 1;
j+= 1;
}
}
}
// Return count of subsegments
return count;
}
// Driver Code
int main()
{
int p[] = {3, 4, 1, 5, 2};
int n = sizeof(p)/sizeof(p[0]);
cout << (Count_Segment(p, n));
return 0;
}
// This code is contributed by
// Surendra_Gangwar
Java
// Java implementation of the approach
import java.util.*;
class GFG
{
// Function to return the count of
// required index pairs
static int Count_Segment(int p[], int n)
{
// To store the required count
int count = 0;
// Array to store the left elements
// upto which current element is maximum
int []upto = new int[n + 1];
for(int i = 0; i < n + 1; i++)
upto[i] = 0;
// Iterating through the whole permutation
// except first and last element
int j = 0,curr = 0;
for (int i = 1; i < n ; i++)
{
// If current element can be maximum
// in a subsegment
if (p[i] > p[i - 1] && p[i] > p[i + 1])
{
// Current maximum
curr = p[i];
// Iterating for smaller values then
// current maximum on left of it
j = i - 1;
while (j >= 0 && p[j] < curr)
{
// Storing left borders
// of the current maximum
upto[p[j]]= curr;
j -= 1;
}
// Iterating for smaller values then
// current maximum on right of it
j = i + 1;
while (j < n && p[j] < curr)
{
// Condition satisfies
if (upto[curr-p[j]] == curr)
count += 1;
j+= 1;
}
}
}
// Return count of subsegments
return count;
}
// Driver Code
public static void main(String[] args)
{
int p[] = {3, 4, 1, 5, 2};
int n = p.length;
System.out.println(Count_Segment(p, n));
}
}
/* This code contributed by PrinciRaj1992 */
Python
# Python3 implementation of the approach
# Function to return the count of
# required index pairs
def Count_Segment(p, n):
# To store the required count
count = 0
# Array to store the left elements
# upto which current element is maximum
upto = [False]*(n + 1)
# Iterating through the whole permutation
# except first and last element
for i in range(1, n-1):
# If current element can be maximum
# in a subsegment
if p[i]>p[i-1] and p[i]>p[i + 1]:
# Current maximum
curr = p[i]
# Iterating for smaller values then
# current maximum on left of it
j = i-1
while j>= 0 and p[j]
C#
// C# implementation of the approach
using System;
class GFG
{
// Function to return the count of
// required index pairs
static int Count_Segment(int []p, int n)
{
// To store the required count
int count = 0;
// Array to store the left elements
// upto which current element is maximum
int []upto = new int[n + 1];
for(int i = 0; i < n + 1; i++)
upto[i] = 0;
// Iterating through the whole permutation
// except first and last element
int j = 0,curr = 0;
for (int i = 1; i < n ; i++)
{
// If current element can be maximum
// in a subsegment
if (p[i] > p[i - 1] && p[i] > p[i + 1])
{
// Current maximum
curr = p[i];
// Iterating for smaller values then
// current maximum on left of it
j = i - 1;
while (j >= 0 && p[j] < curr)
{
// Storing left borders
// of the current maximum
upto[p[j]]= curr;
j= j - 1;
}
// Iterating for smaller values then
// current maximum on right of it
j = i + 1;
while (j < n && p[j] < curr)
{
// Condition satisfies
if (upto[curr-p[j]] == curr)
count += 1;
j= j+ 1;
}
}
}
// Return count of subsegments
return count;
}
// Driver Code
static public void Main ()
{
int []p = {3, 4, 1, 5, 2};
int n = p.Length;
Console.WriteLine(Count_Segment(p, n));
}
}
/* This code contributed by ajit*/
Javascript
输出:
2
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。