There is a simple O(N^2) algorithm. Here is the outline:
- For each element
y
- Search maximum element
x
which is smaller than y
and before y
- Search maximum element
z
which is larger than y
and after y
Step 1 is O(N), Step 2 & 3 can be done in same loop which is O(N), in total it is O(N^2)
There is a O(N lg N) algorithm too, but it is more complicated:
We can precompute in O(N) and query in O(1) for finding maximum in range [l,r]. (Original thought is use segment tree or any RMQ structures, thanks for @PetarPetrovic pointing out)
Also we build a set (sorted list) on the fly while we iterate through each element in the array. The pseudo code is like:
Array A = []
Set S = {}
Ans = 0
For i = 0 to N // O(N)
// A[i] is y
x = binary search S, maximum element in S which is < A[i] //O(lg N)
z = RMQ(i+1, N) // O(lg N), or O(1) if we precompute in O(N)
if(x < A[i] && A[i] < z) Ans = Max(Ans, x*A[i]*z)
Insert A[i] into S // O(lg N)
//Total is O(N lg N)
We try to see A[i]
as the middle element y
.
As we have a sorted set which contains all elements before i
, we can binary search the maximum valid x
using the set. We insert current element into this set afterwards.
We use O(N) to precompute an array and query in O(1) to find maximum in range [i+1, N-1]. The number found is z
.
We update answer if (x,y,z)
is valid tuple and greater than current answer.