给定一个由N个整数组成的数组arr [] ,任务是创建一个大小为N的数组brr [] ,其中brr [i]代表其中arr [i]是最小元素的子数组的数量。
例子:
Input: arr[] = {3, 2, 4}
Output: {1, 3, 1}
Explanation:
For arr[0], there is only one subarray in which 3 is the smallest({3}).
For arr[1], there are three such subarrays where 2 is the smallest({2}, {3, 2}, {2, 4}).
For arr[2], there is only one subarray in which 4 is the smallest({4}).
Input: arr[] = {1, 2, 3, 4, 5}
Output: {5, 4, 3, 2, 1}
天真的方法:最简单的方法是生成给定数组的所有子数组,并对每个数组元素arr [i] ,计算它是最小元素的子数组的数量。
时间复杂度: O(N 3 )
辅助空间: O(N)
高效方法:为了优化上述方法,其思想是找到每个元素的边界索引,直到最小元素为止。对于每个元素,令L和R分别为左侧和右侧的边界索引,arr [i]最小。因此,可以通过以下方式计算所有子数组的数量:
(L + R + 1)*(R + 1)
请按照以下步骤解决问题:
- 将数组元素的所有索引存储在Map中。
- 按升序对数组进行排序。
- 初始化数组boundary [] 。
- 遍历排序后的数组arr [],并使用Binary Search只需插入该元素的索引。假设它在索引i处插入,则其左边界为boundary [i – 1] ,其右边界为boundary [i + 1] 。
- 现在,使用上面的公式,找到子数组的数量,并在结果数组中跟踪该计数。
- 完成上述步骤后,打印存储在结果数组中的所有计数。
下面是上述方法的实现:
C++14
// C++14 program for the above approach
#include
using namespace std;
// Function to find the boundary of every
// element within which it is minimum
int binaryInsert(vector &boundary, int i)
{
int l = 0;
int r = boundary.size() - 1;
// Perform Binary Search
while (l <= r)
{
// Find mid m
int m = (l + r) / 2;
// Update l
if (boundary[m] < i)
l = m + 1;
// Update r
else
r = m - 1;
}
// Inserting the index
boundary.insert(boundary.begin() + l, i);
return l;
}
// Function to required count subarrays
vector countingSubarray(vector arr, int n)
{
// Stores the indices of element
unordered_map index;
for(int i = 0; i < n; i++)
index[arr[i]] = i;
vector boundary = {-1, n};
sort(arr.begin(), arr.end());
// Initialize the output array
vector ans(n, 0);
for(int num : arr)
{
int i = binaryInsert(boundary, index[num]);
// Left boundary, till the
// element is smallest
int l = boundary[i] - boundary[i - 1] - 1;
// Right boundary, till the
// element is smallest
int r = boundary[i + 1] - boundary[i] - 1;
// Calculate the number of subarrays
// based on its boundary
int cnt = l + r + l * r + 1;
// Adding cnt to the ans
ans[index[num]] += cnt;
}
return ans;
}
// Driver Code
int main()
{
int N = 5;
// Given array arr[]
vector arr = { 3, 2, 4, 1, 5 };
// Function call
auto a = countingSubarray(arr, N);
cout << "[";
int n = a.size() - 1;
for(int i = 0; i < n; i++)
cout << a[i] << ", ";
cout << a[n] << "]";
return 0;
}
// This code is contributed by mohit kumar 29
Java
// Java program for the above approach
import java.util.*;
class GFG{
// Function to find the boundary of every
// element within which it is minimum
static int binaryInsert(ArrayList boundary,
int i)
{
int l = 0;
int r = boundary.size() - 1;
// Perform Binary Search
while (l <= r)
{
// Find mid m
int m = (l + r) / 2;
// Update l
if (boundary.get(m) < i)
l = m + 1;
// Update r
else
r = m - 1;
}
// Inserting the index
boundary.add(l, i);
return l;
}
// Function to required count subarrays
static int[] countingSubarray(int[] arr,
int n)
{
// Stores the indices of element
Map index = new HashMap<>();
for(int i = 0; i < n; i++)
index.put(arr[i], i);
ArrayList boundary = new ArrayList<>();
boundary.add(-1);
boundary.add(n);
Arrays.sort(arr);
// Initialize the output array
int[] ans = new int[n];
for(int num : arr)
{
int i = binaryInsert(boundary,
index.get(num));
// Left boundary, till the
// element is smallest
int l = boundary.get(i) -
boundary.get(i - 1) - 1;
// Right boundary, till the
// element is smallest
int r = boundary.get(i + 1) -
boundary.get(i) - 1;
// Calculate the number of subarrays
// based on its boundary
int cnt = l + r + l * r + 1;
// Adding cnt to the ans
ans[index.get(num)] += cnt;
}
return ans;
}
// Driver code
public static void main (String[] args)
{
int N = 5;
// Given array arr[]
int[] arr = { 3, 2, 4, 1, 5 };
// Function call
int[] a = countingSubarray(arr, N);
System.out.print("[");
int n = a.length - 1;
for(int i = 0; i < n; i++)
System.out.print(a[i] + ", ");
System.out.print(a[n] + "]");
}
}
// This code is contributed by offbeat
Python3
# Python3 program for the above approach
# Function to find the boundary of every
# element within which it is minimum
def binaryInsert(boundary, i):
l = 0
r = len(boundary) - 1
# Perform Binary Search
while l <= r:
# Find mid m
m = (l + r) // 2
# Update l
if boundary[m] < i:
l = m + 1
# Update r
else:
r = m - 1
# Inserting the index
boundary.insert(l, i)
return l
# Function to required count subarrays
def countingSubarray(arr, n):
# Stores the indices of element
index = {}
for i in range(n):
index[arr[i]] = i
boundary = [-1, n]
arr.sort()
# Initialize the output array
ans = [0 for i in range(n)]
for num in arr:
i = binaryInsert(boundary, index[num])
# Left boundary, till the
# element is smallest
l = boundary[i] - boundary[i - 1] - 1
# Right boundary, till the
# element is smallest
r = boundary[i + 1] - boundary[i] - 1
# Calculate the number of subarrays
# based on its boundary
cnt = l + r + l * r + 1
# Adding cnt to the ans
ans[index[num]] += cnt
return ans
# Driver Code
N = 5
# Given array arr[]
arr = [3, 2, 4, 1, 5]
# Function Call
print(countingSubarray(arr, N))
C#
// C# program for
// the above approach
using System;
using System.Collections;
using System.Collections.Generic;
class GFG{
// Function to find the
// boundary of every element
// within which it is minimum
static int binaryInsert(ArrayList boundary,
int i)
{
int l = 0;
int r = boundary.Count - 1;
// Perform Binary Search
while (l <= r)
{
// Find mid m
int m = (l + r) / 2;
// Update l
if ((int)boundary[m] < i)
l = m + 1;
// Update r
else
r = m - 1;
}
// Inserting the index
boundary.Insert(l, i);
return l;
}
// Function to required count subarrays
static int[] countingSubarray(int[] arr,
int n)
{
// Stores the indices of element
Dictionary index = new Dictionary();
for(int i = 0; i < n; i++)
index[arr[i]] = i;
ArrayList boundary = new ArrayList();
boundary.Add(-1);
boundary.Add(n);
Array.Sort(arr);
// Initialize the output array
int[] ans = new int[n];
foreach(int num in arr)
{
int i = binaryInsert(boundary,
index[num]);
// Left boundary, till the
// element is smallest
int l = (int)boundary[i] -
(int)boundary[i - 1] - 1;
// Right boundary, till the
// element is smallest
int r = (int)boundary[i + 1] -
(int)boundary[i] - 1;
// Calculate the number of
// subarrays based on its boundary
int cnt = l + r + l * r + 1;
// Adding cnt to the ans
ans[index[num]] += cnt;
}
return ans;
}
// Driver code
public static void Main(string[] args)
{
int N = 5;
// Given array arr[]
int[] arr = {3, 2, 4, 1, 5};
// Function call
int[] a = countingSubarray(arr, N);
Console.Write("[");
int n = a.Length - 1;
for(int i = 0; i < n; i++)
Console.Write(a[i] + ", ");
Console.Write(a[n] + "]");
}
}
// This code is contributed by Rutvik_56
C++14
// C++ implementation of the above approach
#include
using namespace std;
// Function to required count subarrays
vector countingSubarray(vector arr, int n)
{
// For storing count of subarrays
vector a(n);
// For finding next smaller
// element left to a element
// if there is no next smaller
// element left to it than taking -1.
vector nsml(n, -1);
// For finding next smaller
// element right to a element
// if there is no next smaller
// element right to it than taking n.
vector nsmr(n, n);
stack st;
for (int i = n - 1; i >= 0; i--)
{
while (!st.empty() && arr[st.top()] >= arr[i])
st.pop();
nsmr[i] = (!st.empty()) ? st.top() : n;
st.push(i);
}
while (!st.empty())
st.pop();
for (int i = 0; i < n; i++)
{
while (!st.empty() && arr[st.top()] >= arr[i])
st.pop();
nsml[i] = (!st.empty()) ? st.top() : -1;
st.push(i);
}
for (int i = 0; i < n; i++)
{
// Taking exact boundaries
// in which arr[i] is
// minimum
nsml[i]++;
// Similarly for right side
nsmr[i]--;
int r = nsmr[i] - i + 1;
int l = i - nsml[i] + 1;
a[i] = r * l;
}
return a;
}
// Driver Code
int main()
{
int N = 5;
// Given array arr[]
vector arr = { 3, 2, 4, 1, 5 };
// Function call
auto a = countingSubarray(arr, N);
cout << "[";
int n = a.size() - 1;
for (int i = 0; i < n; i++)
cout << a[i] << ", ";
cout << a[n] << "]";
return 0;
}
Java
// Java implementation of the above approach
import java.util.*;
public class gfg
{
// Function to required count subarrays
static int[] countingSubarray(int arr[], int n)
{
// For storing count of subarrays
int a[] = new int[n];
// For finding next smaller
// element left to a element
// if there is no next smaller
// element left to it than taking -1.
int nsml[] = new int[n];
Arrays.fill(nsml, -1);
// For finding next smaller
// element right to a element
// if there is no next smaller
// element right to it than taking n.
int nsmr[] = new int[n];
Arrays.fill(nsmr, n);
Stack st = new Stack();
for(int i = n - 1; i >= 0; i--)
{
while (st.size() > 0 &&
arr[(int)st.peek()] >= arr[i])
st.pop();
nsmr[i] = (st.size() > 0) ? (int)st.peek() : n;
st.push(i);
}
while (st.size() > 0)
st.pop();
for(int i = 0; i < n; i++)
{
while (st.size() > 0 &&
arr[(int)st.peek()] >= arr[i])
st.pop();
nsml[i] = (st.size() > 0) ? (int)st.peek() : -1;
st.push(i);
}
for(int i = 0; i < n; i++)
{
// Taking exact boundaries
// in which arr[i] is
// minimum
nsml[i]++;
// Similarly for right side
nsmr[i]--;
int r = nsmr[i] - i + 1;
int l = i - nsml[i] + 1;
a[i] = r * l;
}
return a;
}
// Driver code
public static void main(String[] args)
{
int N = 5;
// Given array arr[]
int arr[] = { 3, 2, 4, 1, 5 };
// Function call
int a[] = countingSubarray(arr, N);
System.out.print("[");
int n = a.length - 1;
for(int i = 0; i < n; i++)
System.out.print(a[i] + ", ");
System.out.print(a[n] + "]");
}
}
// This code is contributed by divyesh072019.
Python3
# Python implementation of the above approach
# Function to required count subarrays
def countingSubarray(arr, n):
# For storing count of subarrays
a = [0 for i in range(n)]
# For finding next smaller
# element left to a element
# if there is no next smaller
# element left to it than taking -1.
nsml = [-1 for i in range(n)]
# For finding next smaller
# element right to a element
# if there is no next smaller
# element right to it than taking n.
nsmr = [n for i in range(n)]
st = []
for i in range(n - 1, -1, -1):
while(len(st) > 0 and arr[st[-1]] >= arr[i]):
del st[-1]
if(len(st) > 0):
nsmr[i] = st[-1]
else:
nsmr[i] = n
st.append(i)
while(len(st) > 0):
del st[-1]
for i in range(n):
while(len(st) > 0 and arr[st[-1]] >= arr[i]):
del st[-1]
if(len(st) > 0):
nsml[i] = st[-1]
else:
nsml[i] = -1
st.append(i)
for i in range(n):
# Taking exact boundaries
# in which arr[i] is
# minimum
nsml[i] += 1
# Similarly for right side
nsmr[i] -= 1
r = nsmr[i] - i + 1;
l = i - nsml[i] + 1;
a[i] = r * l;
return a;
# Driver code
N = 5
# Given array arr[]
arr = [3, 2, 4, 1, 5 ]
# Function call
a = countingSubarray(arr, N)
print(a)
# This code is contributed by rag2127
C#
// C# implementation of the above approach
using System;
using System.Collections;
class GFG{
// Function to required count subarrays
static int[] countingSubarray(int[] arr, int n)
{
// For storing count of subarrays
int[] a = new int[n];
// For finding next smaller
// element left to a element
// if there is no next smaller
// element left to it than taking -1.
int[] nsml = new int[n];
Array.Fill(nsml, -1);
// For finding next smaller
// element right to a element
// if there is no next smaller
// element right to it than taking n.
int[] nsmr = new int[n];
Array.Fill(nsmr, n);
Stack st = new Stack();
for(int i = n - 1; i >= 0; i--)
{
while (st.Count > 0 &&
arr[(int)st.Peek()] >= arr[i])
st.Pop();
nsmr[i] = (st.Count > 0) ? (int)st.Peek() : n;
st.Push(i);
}
while (st.Count > 0)
st.Pop();
for(int i = 0; i < n; i++)
{
while (st.Count > 0 &&
arr[(int)st.Peek()] >= arr[i])
st.Pop();
nsml[i] = (st.Count > 0) ? (int)st.Peek() : -1;
st.Push(i);
}
for(int i = 0; i < n; i++)
{
// Taking exact boundaries
// in which arr[i] is
// minimum
nsml[i]++;
// Similarly for right side
nsmr[i]--;
int r = nsmr[i] - i + 1;
int l = i - nsml[i] + 1;
a[i] = r * l;
}
return a;
}
// Driver code
static void Main()
{
int N = 5;
// Given array arr[]
int[] arr = { 3, 2, 4, 1, 5 };
// Function call
int[] a = countingSubarray(arr, N);
Console.Write("[");
int n = a.Length - 1;
for(int i = 0; i < n; i++)
Console.Write(a[i] + ", ");
Console.Write(a[n] + "]");
}
}
// This code is contributed by divyeshrabadiya07
[1, 4, 1, 8, 1]
时间复杂度: O(N log N)
辅助空间: O(N)
最有效的方法:
为了优化上述方法,我们可以使用堆栈数据结构。
- 想法是,对于每个(1≤i≤N),我们将尝试找到在它右边的下一个较小元素的index(R)和在它左边的下一个较小元素的index(L) 。
- 现在我们有了边界索引(L,R) ,其中arr [i]是最小值,因此每个i(0-base)的子数组总数将是(Ri)*(iL)。
以下是该想法的实现:
C++ 14
// C++ implementation of the above approach
#include
using namespace std;
// Function to required count subarrays
vector countingSubarray(vector arr, int n)
{
// For storing count of subarrays
vector a(n);
// For finding next smaller
// element left to a element
// if there is no next smaller
// element left to it than taking -1.
vector nsml(n, -1);
// For finding next smaller
// element right to a element
// if there is no next smaller
// element right to it than taking n.
vector nsmr(n, n);
stack st;
for (int i = n - 1; i >= 0; i--)
{
while (!st.empty() && arr[st.top()] >= arr[i])
st.pop();
nsmr[i] = (!st.empty()) ? st.top() : n;
st.push(i);
}
while (!st.empty())
st.pop();
for (int i = 0; i < n; i++)
{
while (!st.empty() && arr[st.top()] >= arr[i])
st.pop();
nsml[i] = (!st.empty()) ? st.top() : -1;
st.push(i);
}
for (int i = 0; i < n; i++)
{
// Taking exact boundaries
// in which arr[i] is
// minimum
nsml[i]++;
// Similarly for right side
nsmr[i]--;
int r = nsmr[i] - i + 1;
int l = i - nsml[i] + 1;
a[i] = r * l;
}
return a;
}
// Driver Code
int main()
{
int N = 5;
// Given array arr[]
vector arr = { 3, 2, 4, 1, 5 };
// Function call
auto a = countingSubarray(arr, N);
cout << "[";
int n = a.size() - 1;
for (int i = 0; i < n; i++)
cout << a[i] << ", ";
cout << a[n] << "]";
return 0;
}
Java
// Java implementation of the above approach
import java.util.*;
public class gfg
{
// Function to required count subarrays
static int[] countingSubarray(int arr[], int n)
{
// For storing count of subarrays
int a[] = new int[n];
// For finding next smaller
// element left to a element
// if there is no next smaller
// element left to it than taking -1.
int nsml[] = new int[n];
Arrays.fill(nsml, -1);
// For finding next smaller
// element right to a element
// if there is no next smaller
// element right to it than taking n.
int nsmr[] = new int[n];
Arrays.fill(nsmr, n);
Stack st = new Stack();
for(int i = n - 1; i >= 0; i--)
{
while (st.size() > 0 &&
arr[(int)st.peek()] >= arr[i])
st.pop();
nsmr[i] = (st.size() > 0) ? (int)st.peek() : n;
st.push(i);
}
while (st.size() > 0)
st.pop();
for(int i = 0; i < n; i++)
{
while (st.size() > 0 &&
arr[(int)st.peek()] >= arr[i])
st.pop();
nsml[i] = (st.size() > 0) ? (int)st.peek() : -1;
st.push(i);
}
for(int i = 0; i < n; i++)
{
// Taking exact boundaries
// in which arr[i] is
// minimum
nsml[i]++;
// Similarly for right side
nsmr[i]--;
int r = nsmr[i] - i + 1;
int l = i - nsml[i] + 1;
a[i] = r * l;
}
return a;
}
// Driver code
public static void main(String[] args)
{
int N = 5;
// Given array arr[]
int arr[] = { 3, 2, 4, 1, 5 };
// Function call
int a[] = countingSubarray(arr, N);
System.out.print("[");
int n = a.length - 1;
for(int i = 0; i < n; i++)
System.out.print(a[i] + ", ");
System.out.print(a[n] + "]");
}
}
// This code is contributed by divyesh072019.
Python3
# Python implementation of the above approach
# Function to required count subarrays
def countingSubarray(arr, n):
# For storing count of subarrays
a = [0 for i in range(n)]
# For finding next smaller
# element left to a element
# if there is no next smaller
# element left to it than taking -1.
nsml = [-1 for i in range(n)]
# For finding next smaller
# element right to a element
# if there is no next smaller
# element right to it than taking n.
nsmr = [n for i in range(n)]
st = []
for i in range(n - 1, -1, -1):
while(len(st) > 0 and arr[st[-1]] >= arr[i]):
del st[-1]
if(len(st) > 0):
nsmr[i] = st[-1]
else:
nsmr[i] = n
st.append(i)
while(len(st) > 0):
del st[-1]
for i in range(n):
while(len(st) > 0 and arr[st[-1]] >= arr[i]):
del st[-1]
if(len(st) > 0):
nsml[i] = st[-1]
else:
nsml[i] = -1
st.append(i)
for i in range(n):
# Taking exact boundaries
# in which arr[i] is
# minimum
nsml[i] += 1
# Similarly for right side
nsmr[i] -= 1
r = nsmr[i] - i + 1;
l = i - nsml[i] + 1;
a[i] = r * l;
return a;
# Driver code
N = 5
# Given array arr[]
arr = [3, 2, 4, 1, 5 ]
# Function call
a = countingSubarray(arr, N)
print(a)
# This code is contributed by rag2127
C#
// C# implementation of the above approach
using System;
using System.Collections;
class GFG{
// Function to required count subarrays
static int[] countingSubarray(int[] arr, int n)
{
// For storing count of subarrays
int[] a = new int[n];
// For finding next smaller
// element left to a element
// if there is no next smaller
// element left to it than taking -1.
int[] nsml = new int[n];
Array.Fill(nsml, -1);
// For finding next smaller
// element right to a element
// if there is no next smaller
// element right to it than taking n.
int[] nsmr = new int[n];
Array.Fill(nsmr, n);
Stack st = new Stack();
for(int i = n - 1; i >= 0; i--)
{
while (st.Count > 0 &&
arr[(int)st.Peek()] >= arr[i])
st.Pop();
nsmr[i] = (st.Count > 0) ? (int)st.Peek() : n;
st.Push(i);
}
while (st.Count > 0)
st.Pop();
for(int i = 0; i < n; i++)
{
while (st.Count > 0 &&
arr[(int)st.Peek()] >= arr[i])
st.Pop();
nsml[i] = (st.Count > 0) ? (int)st.Peek() : -1;
st.Push(i);
}
for(int i = 0; i < n; i++)
{
// Taking exact boundaries
// in which arr[i] is
// minimum
nsml[i]++;
// Similarly for right side
nsmr[i]--;
int r = nsmr[i] - i + 1;
int l = i - nsml[i] + 1;
a[i] = r * l;
}
return a;
}
// Driver code
static void Main()
{
int N = 5;
// Given array arr[]
int[] arr = { 3, 2, 4, 1, 5 };
// Function call
int[] a = countingSubarray(arr, N);
Console.Write("[");
int n = a.Length - 1;
for(int i = 0; i < n; i++)
Console.Write(a[i] + ", ");
Console.Write(a[n] + "]");
}
}
// This code is contributed by divyeshrabadiya07
[1, 4, 1, 8, 1]
时间复杂度: O(N)
辅助空间: O(N)