Given an array of size N, each element of the array lies between [0, N-1] i.e., the given array is a permutation. The task is to determine the number of subarrays whose MEX is greater than the Median.
Note: MEX is the smallest whole number that is not present in the array.
Examples:
Input: N=4, arr=[0, 2, 1, 3]
Output: 4
Explanation: The subarrays whose MEX is greater than Median are: [0], [0, 2], [0, 2, 1], and [0, 2, 1, 3].Input: N=4, arr=[1, 0]
Output: 2
Explanation: The subarrays whose MEX is greater than Median are: [0], [1, 0].
MEX Subarray Count using Two Pointers:
We can firstly observe the MEX of any subarray will be in between 0 to N. So we can calculate the answer for a fixed value of MEX. Now, for a fixed value of MEX , let l be the index of left-most number 0, 1, 2, .... mex-1 and r be the index of right-most number 0, 1, 2, ... mex-1. Let curr be the current length of the subarray i.e., curr=(r-l)+1. If curr is less than equal to 2*MEX, then MED of the subarray will arr[l...r] will be in between [0.....MEX-1], so number of subarrays can be calculated with some formulas. If curr greater than 2*MEX then MED of subarray will be greater.
Follow the steps to solve the problem:
- Create the index and frequency array to store index and frequency of elements. Let ans variable store the number of subarrays whose MEX is greater than the Median.
- Maintain two pointer l and r which stores index of left-most number 0, 1, 2, .... mex-1 and r be the index of right-most number 0, 1, 2, ... mex-1.
- Run a loop while
mexis less than or equal toN:- Calculate the size of current subarray, curr=(r-l)+1 and let len=2*mex.
- If curr<=len, then Median of subarray is less than mex and we update the answer by some formulas.
- Else, answer won't be updated.
- Update l, r and mex.
- Return the ans
Below is the implementation of above approach:
#include <bits/stdc++.h>
using namespace std;
int solve(vector<int> a, int N) {
vector<int> idx(N + 2);
vector<int> frq(N + 2, 0);
// Store the indices of elements in the array
for (int i = 0; i < N; i++) {
idx[a[i]] = i;
}
// Base case: If the array has only one element, return 1
if (N == 1) {
return 1;
}
int ans = 0; // Initialize the answer to 0
int mex = 1; // Initialize mex to 1
int l = idx[0]; // Initialize l to the index of 0
int r = idx[0]; // Initialize r to the index of 0
frq[0] = 1; // Mark the frequency of 0 as 1
// Loop until mex reaches N
while (mex <= N) {
int num1 = 0, num2 = 0;
int len = mex * 2;
int curr = (r - l + 1);
int op = len - curr;
// Calculate num1 and num2 based on the position of mex
if (mex == N) {
num1 = l;
num2 = (N - 1) - r;
} else {
if (idx[mex] < l) {
num1 = (l - idx[mex]) - 1;
num2 = (N - 1) - r;
} else {
num1 = l;
num2 = (idx[mex] - r) - 1;
}
}
// Check conditions and update the answer
if (op == 0) {
ans++;
} else if (op > 0) {
num1 = min(op, num1);
num2 = min(op, num2);
if (num1 > num2)
swap(num1, num2);
int ext = (num2 + 1) * (min((op - num2) + 1, num1 + 1));
int rem = max(0, num1 - (op - num2));
int m = num2;
int x = max(0, m - rem);
int ext1 = (m * (m + 1)) / 2;
int ext2 = (x * (x + 1)) / 2;
ans = ans + ext + (ext1 - ext2);
}
// Break the loop if mex reaches N
if (mex == N)
break;
// Update l and r based on the position of mex
if (idx[mex] < l) {
l--;
while (l != idx[mex]) {
frq[a[l]] = 1;
l--;
}
frq[a[l]] = 1;
} else if (idx[mex] > r) {
r++;
while (r != idx[mex]) {
frq[a[r]] = 1;
r++;
}
frq[a[r]] = 1;
}
// Update mex until a non-zero frequency element is found
while (frq[mex] != 0) {
mex++;
}
}
return ans;
}
// Driver Code
int main() {
int N = 4;
vector<int> arr = {0, 2, 1, 3};
cout << solve(arr, N);
}
// Java Implementation:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int N = 4;
int[] arr = {0, 2, 1, 3};
System.out.println(solve(arr, N));
}
public static int solve(int[] a, int N) {
int[] idx = new int[N + 2];
int[] frq = new int[N + 2];
// Store the indices of elements in the array
for (int i = 0; i < N; i++) {
idx[a[i]] = i;
}
// Base case: If the array has only one element, return 1
if (N == 1) {
return 1;
}
int ans = 0; // Initialize the answer to 0
int mex = 1; // Initialize mex to 1
int l = idx[0]; // Initialize l to the index of 0
int r = idx[0]; // Initialize r to the index of 0
frq[0] = 1; // Mark the frequency of 0 as 1
// Loop until mex reaches N
while (mex <= N) {
int num1 = 0, num2 = 0;
int len = mex * 2;
int curr = (r - l + 1);
int op = len - curr;
// Calculate num1 and num2 based on the position of mex
if (mex == N) {
num1 = l;
num2 = (N - 1) - r;
} else {
if (idx[mex] < l) {
num1 = (l - idx[mex]) - 1;
num2 = (N - 1) - r;
} else {
num1 = l;
num2 = (idx[mex] - r) - 1;
}
}
// Check conditions and update the answer
if (op == 0) {
ans++;
} else if (op > 0) {
num1 = Math.min(op, num1);
num2 = Math.min(op, num2);
if (num1 > num2)
swap(num1, num2);
int ext = (num2 + 1) * (Math.min((op - num2) + 1, num1 + 1));
int rem = Math.max(0, num1 - (op - num2));
int m = num2;
int x = Math.max(0, m - rem);
int ext1 = (m * (m + 1)) / 2;
int ext2 = (x * (x + 1)) / 2;
ans = ans + ext + (ext1 - ext2);
}
// Break the loop if mex reaches N
if (mex == N)
break;
// Update l and r based on the position of mex
if (idx[mex] < l) {
l--;
while (l != idx[mex]) {
frq[a[l]] = 1;
l--;
}
frq[a[l]] = 1;
} else if (idx[mex] > r) {
r++;
while (r != idx[mex]) {
frq[a[r]] = 1;
r++;
}
frq[a[r]] = 1;
}
// Update mex until a non-zero frequency element is found
while (frq[mex] != 0) {
mex++;
}
}
return ans;
}
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
}
// This code is contributed by Sakshi
def solve(a, N):
idx = [0] * (N + 2)
frq = [0] * (N + 2)
# Store the indices of elements in the array
for i in range(N):
idx[a[i]] = i
# Base case: If the array has only one element, return 1
if N == 1:
return 1
ans = 0 # Initialize the answer to 0
mex = 1 # Initialize mex to 1
l = idx[0] # Initialize l to the index of 0
r = idx[0] # Initialize r to the index of 0
frq[0] = 1 # Mark the frequency of 0 as 1
# Loop until mex reaches N
while mex <= N:
num1 = 0
num2 = 0
len = mex * 2
curr = r - l + 1
op = len - curr
# Calculate num1 and num2 based on the position of mex
if mex == N:
num1 = l
num2 = N - 1 - r
else:
if idx[mex] < l:
num1 = l - idx[mex] - 1
num2 = N - 1 - r
else:
num1 = l
num2 = idx[mex] - r - 1
# Check conditions and update the answer
if op == 0:
ans += 1
elif op > 0:
num1 = min(op, num1)
num2 = min(op, num2)
if num1 > num2:
num1, num2 = num2, num1
ext = (num2 + 1) * (min(op - num2 + 1, num1 + 1))
rem = max(0, num1 - (op - num2))
m = num2
x = max(0, m - rem)
ext1 = (m * (m + 1)) // 2
ext2 = (x * (x + 1)) // 2
ans = ans + ext + (ext1 - ext2)
# Break the loop if mex reaches N
if mex == N:
break
# Update l and r based on the position of mex
if idx[mex] < l:
l -= 1
while l != idx[mex]:
frq[a[l]] = 1
l -= 1
frq[a[l]] = 1
elif idx[mex] > r:
r += 1
while r != idx[mex]:
frq[a[r]] = 1
r += 1
frq[a[r]] = 1
# Update mex until a non-zero frequency element is found
while frq[mex] != 0:
mex += 1
return ans
# Driver Code
N = 4
arr = [0, 2, 1, 3]
print(solve(arr, N))
// C# program for the above approach
using System;
using System.Collections.Generic;
class Program
{
static int Solve(List<int> a, int N)
{
List<int> idx = new List<int>(new int[N + 2]);
List<int> frq = new List<int>(new int[N + 2]);
// Store the indices of elements in the array
for (int i = 0; i < N; i++)
{
idx[a[i]] = i;
}
// Base case: If the array has only one element, return 1
if (N == 1)
{
return 1;
}
int ans = 0; // Initialize the answer to 0
int mex = 1; // Initialize mex to 1
int l = idx[0]; // Initialize l to the index of 0
int r = idx[0]; // Initialize r to the index of 0
frq[0] = 1; // Mark the frequency of 0 as 1
// Loop until mex reaches N
while (mex <= N)
{
int num1 = 0, num2 = 0;
int len = mex * 2;
int curr = (r - l + 1);
int op = len - curr;
// Calculate num1 and num2 based on the position of mex
if (mex == N)
{
num1 = l;
num2 = (N - 1) - r;
}
else
{
if (idx[mex] < l)
{
num1 = (l - idx[mex]) - 1;
num2 = (N - 1) - r;
}
else
{
num1 = l;
num2 = (idx[mex] - r) - 1;
}
}
// Check conditions and update the answer
if (op == 0)
{
ans++;
}
else if (op > 0)
{
num1 = Math.Min(op, num1);
num2 = Math.Min(op, num2);
if (num1 > num2)
Swap(ref num1, ref num2);
int ext = (num2 + 1) * (Math.Min((op - num2) + 1, num1 + 1));
int rem = Math.Max(0, num1 - (op - num2));
int m = num2;
int x = Math.Max(0, m - rem);
int ext1 = (m * (m + 1)) / 2;
int ext2 = (x * (x + 1)) / 2;
ans = ans + ext + (ext1 - ext2);
}
// Break the loop if mex reaches N
if (mex == N)
break;
// Update l and r based on the position of mex
if (idx[mex] < l)
{
l--;
while (l != idx[mex])
{
frq[a[l]] = 1;
l--;
}
frq[a[l]] = 1;
}
else if (idx[mex] > r)
{
r++;
while (r != idx[mex])
{
frq[a[r]] = 1;
r++;
}
frq[a[r]] = 1;
}
// Update mex until a non-zero frequency element is found
while (frq[mex] != 0)
{
mex++;
}
}
return ans;
}
// Helper method to swap two integers
static void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
// Driver Code
static void Main()
{
int N = 4;
List<int> arr = new List<int> { 0, 2, 1, 3 };
Console.WriteLine(Solve(arr, N));
}
}
// This code is contributed by Susobhan Akhuli
// JavaScript code for the above aprpoach:
function solve(a, N) {
let idx = new Array(N + 2).fill(0);
let frq = new Array(N + 2).fill(0);
// Store the indices of elements in the array
for (let i = 0; i < N; i++) {
idx[a[i]] = i;
}
// Base case: If the array has only one element, return 1
if (N === 1) {
return 1;
}
let ans = 0; // Initialize the answer to 0
let mex = 1; // Initialize mex to 1
let l = idx[0]; // Initialize l to the index of 0
let r = idx[0]; // Initialize r to the index of 0
frq[0] = 1; // Mark the frequency of 0 as 1
// Loop until mex reaches N
while (mex <= N) {
let num1 = 0, num2 = 0;
let len = mex * 2;
let curr = r - l + 1;
let op = len - curr;
// Calculate num1 and num2 based on the position of mex
if (mex === N) {
num1 = l;
num2 = (N - 1) - r;
}
else {
if (idx[mex] < l) {
num1 = (l - idx[mex]) - 1;
num2 = (N - 1) - r;
}
else {
num1 = l;
num2 = (idx[mex] - r) - 1;
}
}
// Check conditions and update the answer
if (op === 0) {
ans++;
}
else if (op > 0) {
num1 = Math.min(op, num1);
num2 = Math.min(op, num2);
if (num1 > num2) {
[num1, num2] = [num2, num1];
}
let ext = (num2 + 1) * Math.min((op - num2) + 1, num1 + 1);
let rem = Math.max(0, num1 - (op - num2));
let m = num2;
let x = Math.max(0, m - rem);
let ext1 = (m * (m + 1)) / 2;
let ext2 = (x * (x + 1)) / 2;
ans = ans + ext + (ext1 - ext2);
}
// Break the loop if mex reaches N
if (mex === N) {
break;
}
// Update l and r based on the position of mex
if (idx[mex] < l) {
l--;
while (l !== idx[mex]) {
frq[a[l]] = 1;
l--;
}
frq[a[l]] = 1;
}
else if (idx[mex] > r) {
r++;
while (r !== idx[mex]) {
frq[a[r]] = 1;
r++;
}
frq[a[r]] = 1;
}
// Update mex until a non-zero frequency element is found
while (frq[mex] !== 0) {
mex++;
}
}
return ans;
}
// Driver Code
let N = 4;
let arr = [0, 2, 1, 3];
console.log(solve(arr, N));
Output
4
Time Complexity: O(N)
Auxiliary Space: O(N)