简体   繁体   中英

Find ascending triples in a list

I encountered the problem in a programming interview and have no idea about it by now.

A list whose length is n, the elements in it are all positive integers without order. To find out all possible triples (a, b, c), that a < b < c, and a appears before b and b before c in the list.

And analyse the time complexity of your algorithm.

No general algorithm can be faster than O(n^3), as given a sorted input of distinct elements then the output will have size O(n^3), so just to produce the output will take time proportional. Indeed even a randomly generated list of integers will already have n^3 triples up until constant factors.

That given you could simply iterate over all possible triples in list order, and compare them for sorted order. This naive solution is already the best it can be asymptotically (that is O(n^3))

for (int i = 0; i < n; i++)
    for (int j = i+1; j < n; j++)
        for (int k = j+1; k < n; k++)
            if (X[i] < X[j] && X[j] < X[k)
                output(X[i],X[j],X[k])

I suspect you may have a transcription error in your problem statement - or else the question is supposed to be a very easy short coding exercise.

If it is known that there are only a small set of triples (say k), then you may prefer to find all the triples by storing pointers to the previous smallest element.

ALGORITHM

Prepare an empty data structure (possible choices described later).

Prepare an empty array B of length n.

Then for each element c in the list:

  1. Store the index (in the array B) of the most recent element in the list that is smaller than c (if it exists) using the data structure.
  2. Store c (and its index in the original list) in the data structure
  3. Then use array B to find all elements b smaller than c, and then again to find all elements a smaller than b, and emit all these combinations as output triples.

DATA STRUCTURE

The data structure needs to be able to store value,position pairs to make it easy to find the largest position (ie most recent) over all elements with value less than c.

One easy way to do this if the range of allowed values is fairly small is to use a series of arrays where A[k][x] stores the maximum position for all elements in the range [x*2^k,(x+1)*2^k).

If the values have up to M bits (ie the values are in the range 0 to 2^M-1) then updating or accessing this data structure are both O(M) operations.

COMPLEXITY

The given method is O(nM+k).

If the values have a larger range, then you could use a form of binary search tree instead of the series of arrays, or instead sort the values and replace the values with their ordinal value. This would then have complexity O(nlogn+k).

COUNTING TRIPLES

If you just wish to know the total number of triples of this form then you can do this in O(n).

The idea is similar to before:

  1. Find the most recent smaller element for each index, and the count of smaller elements for each index
  2. Find the next greater element for each index, and the count of greater elements
  3. Compute the sum of the product of the count of smaller elements and the count of larger elements for each index.

To make this O(n) we need to be able to find the next greater element in O(n). This can be done by:

  1. Push the current index i to the stack
  2. while A[top(stack)] < A[i+1], pop an index x off the stack and store NGE[x]=i+1
  3. increment i and return to step 1

We also need to be able to find the count of greater elements in O(n). Once the NGE array has been prepared, we can find the counts by iterating backwards over the array and computing

count_greater_elements[i] = count_greater_elements[ NGE[i] ] + 1 if NGE[i] is defined
                          = 0 otherwise

The most recent smaller elements and counts can be computed in an analogous way.

N^2 solution for general case (to count all such triples, not output them all; output will take n^3 just because of its size):

for each number X in array lets count amount of numbers less than X with indexes less than x and amount of numbers greater than X with indexes greater than X. Than for each X we can get number of triples in which X is the middle element just as less[X] * greater[X]. The answer is sum of such products.

int calc(vector<int> numbers) {
 int n = numbers.size();
 vector<int> less(n), more(n);
 for (int i = 0; i < n; i++)
  for (int j = i + 1; j < n; j++)
   if (numbers[i] < numbers[j])
    less[j]++, more[i]++;

 int res = 0;
 for (int i = 0; i < n; i++)
  res += less[i] * more[i];

 return res;
}

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