简体   繁体   中英

Minimum elements in all contiguous subarrays

I saw a question where it was asked to find minimum of all contiguous subarrays. For eg. For an array A=[1,2,3], the answer will be an array B containing [1,2,3,1,2,1].
How -

B[0] = 1 for subarray A[0]  
B[1] = 2 for subarray A[1]  
B[2] = 3 for subarray A[2]  
B[3] = 1 for subarray A[0,1]  
B[4] = 2 for subarray A[1,2]  
B[5] = 1 for subarray A[0,1,2]

What I did, is, constructed a segment tree, but it doesn't contains minimum of all contiguous subarrays.
I don't think I can use "Dequeues" either, because I don't have to find min in a subarray of particular length.
So, how can I get min. of all contiguous subarrays(that B array)?

Here is the implementation using Segment tree:

#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <iostream>

using namespace std;

int Mid(int s, int e) {  return s + (e -s)/2;  }
int RMQUtil(int *st, int ss, int se, int qs, int qe, int index) {
    if (qs <= ss && qe >= se)
        return st[index];
    if (se < qs || ss > qe)
        return INT_MAX;

    int mid = Mid(ss, se);
    return min(RMQUtil(st, ss, mid, qs, qe, 2*index+1),
                  RMQUtil(st, mid+1, se, qs, qe, 2*index+2));
}
int RMQ(int *st, int n, int qs, int qe) {
    if (qs < 0 || qe > n-1 || qs > qe)
    {
        printf("Invalid Input");
        return -1;
    }

    return RMQUtil(st, 0, n-1, qs, qe, 0);
}
int constructSTUtil(int arr[], int ss, int se, int *st, int si) {
    if (ss == se) {
        st[si] = arr[ss];
        return arr[ss];
    }
    int mid = Mid(ss, se);
    st[si] =  min(constructSTUtil(arr, ss, mid, st, si*2+1),
                     constructSTUtil(arr, mid+1, se, st, si*2+2));
    return st[si];
}
int *constructST(int arr[], int n) {
    // Allocate memory for segment tree
    int x = (int)(ceil(log2(n)));
    int max_size = 2*(int)pow(2, x) - 1;
    int *st = new int[max_size];

    // Fill the allocated memory st
    constructSTUtil(arr, 0, n-1, st, 0);
    return st;
}
int main()
{
    int arr[] = {1, 2, 3};
    int n = sizeof(arr)/sizeof(arr[0]);

    int *st = constructST(arr, n);

    int qs = 0; //start
    int qe = 2; //end
    int s = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n - s; ++j) {
            cout << RMQ(st, n, j, j + s) << " ";
        }
        s += 1;
    }
    cout << endl;

    return 0;
}

Of course you can use a deque. Find a way that the smallest element always appears at the front of the Q and the size of Q never exceeds L. The complexity: O(n)

A simple O(n^2) solution (instead of O(n^2 log n) with a segment tree) is to use dynamic programing-ish algorithm:

You start with an array T that is equal to A, but in every step, you compute one more minimum ahead in each element in T.

T1 = min(1..1), min(2..2), min(3..3)

T2 = min(1..2), min(2..3), <bogus>

T3 = min(1..3), <bogus>  , <bogus>

Here's an example in Python:

def solve(A):
    T = list(A)
    B = list(A)

    for k in range(1, len(A)):
        for i in range(len(A)-k):
            T[i] = min(T[i], A[i+k])
            B.append(T[i])

    return B

print solve([1,2,3])

Let's see that you can simply sort the input array and then you have got:

a_1 <= a_2 <= ... <= a_n ,

then the question is: how many times each of them exists in B ?

So take a_i, it is existing in B only when a_i is in the following contiguous subarrays:

a_i
a_i a_(i+1)
...
a_i a_(i+1) ... a_n

So a_i exists n-i+1 times in B .

So then you can simply create B with O(n^2) complexity (number of all the contiguous subarrays is C(n, 2) = O(n^2)).

UPDATE : This solution is OK only for sorted A.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM