📌  相关文章
📜  计算最小的每个数组元素的子数组

📅  最后修改于: 2021-05-17 20:38:30             🧑  作者: Mango

给定一个由N个整数组成的数组arr [] ,任务是创建一个大小为N的数组brr [] ,其中brr [i]代表其中arr [i]是最小元素的子数组的数量。

例子:

天真的方法:最简单的方法是生成给定数组的所有子数组,并对每个数组元素arr [i] ,计算它是最小元素的子数组的数量。

时间复杂度: O(N 3 )
辅助空间: O(N)

高效方法:为了优化上述方法,其思想是找到每个元素的边界索引,直到最小元素为止。对于每个元素,令LR分别为左侧和右侧的边界索引,arr [i]最小。因此,可以通过以下方式计算所有子数组的数量:

请按照以下步骤解决问题:

  1. 将数组元素的所有索引存储在Map中。
  2. 按升序对数组进行排序。
  3. 初始化数组boundary []
  4. 遍历排序后的数组arr [],并使用Binary Search只需插入该元素的索引。假设它在索引i处插入,则其左边界为boundary [i – 1] ,其右边界为boundary [i + 1]
  5. 现在,使用上面的公式,找到子数组的数量,并在结果数组中跟踪该计数。
  6. 完成上述步骤后,打印存储在结果数组中的所有计数。

下面是上述方法的实现:

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


Javascript


输出
[1, 4, 1, 8, 1]

时间复杂度: O(N log N)
辅助空间: O(N)

最有效的方法:

为了优化上述方法,我们可以使用堆栈数据结构。

  1. 想法是,对于每个(1≤i≤N),我们将尝试找到在它右边的下一个较小元素的index(R)和在它左边的下一个较小元素的index(L)
  2. 现在我们有了边界索引(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

Java脚本


输出
[1, 4, 1, 8, 1]

时间复杂度: O(N)  
辅助空间: O(N)