This was the interview question I had from a tech company. I got it wrong, which I think doomed my chances, but I honestly I still cannot figure out the answer... here's the question. Assume that all elements of the sequence are unique.
We have two finite sequences: X={Xi}, Y={Yi} where Yi is a sub-sequence of Xi.
Let's write them as separate arrays: [X1, X2, ..., Xn], [Y1, Y2, ..., Yk] where n is the length of X, k is the length of Y, and obviously, since Y is a sub-sequence of X, we have n>=k.
For instance
X=[1, 10, 5, 7, 11, -4, 9, 5]
y=[10, 7, -4, 9]
Then for each element in Y, we want to find the number of elements in X which 1) appear after that element and 2) greater than that element.
Using the example above
X=[1, 10, 5, 7, 11, -4, 9, 5]
y=[10, 7, -4, 9]
ans=[1, 2, 2, 0]
explanation:
the first element of ans is 1 because only 11 appears after 10 and greater than 10 in X,
so there's only 1 element
second element of ans is 2 since 11, 9 both appear after 7 in X, so there are 2 elements
that appear after 7 and greater than 7.
the third element of ans is also 2 since 9, 5 appear after -4 and are both greater than
-4 in X.
the fourth element is 0 since no element in X appears after and greater than 9.
The interviewer wanted me to solve it in O(N) time complexity where N is the length of X. I did not find how.
Anybody has an idea?
If have an algorithm that can solve this problem, then by setting Y = X, you can make it provide enough information to sort X without any further comparisons among elements in X. Therefore, you can't do this in linear time under the usual assumptions, i.e., arbitrary integers in X that you can do operations on in constant time, but no constant bound on their size.
You can do it in O(N log N) time pretty easily by walking backwards through X and maintaining an order statistic tree of the elements seen so far. See https://en.wikipedia.org/wiki/Order_statistic_tree
I think it's impossible same as it's impossible for sorting and here is the reason
For solving this we should save state for previous calculation in limited number variable, for example store addition, subtraction or multiply.
So if there is a big number in A thats not in B its very clear it's not usefull at all, and we already know the only possible solution is to save previous state in limited variable, So we can't have numbers that related only to item in A.
So far we know to solve this is we should figure out the saving state algorithm, for saving state we can only store some number that represent for all previous numbers for current element in Y all of these calculation its not helping because we dont know the next item in Y (for example the current number is -1000 and next number is 3000 and other number in X is 1,2,3). so because of that we cant have any stored number that related to current element in Y. also we cant have any number that's not related to Y(as its usefull at all)
Related
I am searching an algorithm which gives me the next permutation with a specific strength.
A permutation of length n is defined with the elements (1,2,3,...n)
What is the strength of a permutation?
The strength of a permutation with length 10 is definded as |a1-a2|+|a2-a3|+...+|a9-a10|+|a10-a1|.
For example:
(1,2,3,4,5,6) has the strength 10
(1,2,6,3,4,5) has the strength 14
Exist there a formula to compute the next permutation of a given strength and length, or its necesary to compute all elements?
Is ranking/unranking of the subsets possible?
The next permutation function should return the next lexicographical permutation within the subset defined by the given strength and length and without compute the intermediate permutations different strengths.
This is a nicely masked problem in combinatorics. First, note that this is a ring of integers; the linear "array" is an implementation choice, rather than part of the strength analysis. Let's look at the second case, given as (1,2,6,3,4,5):
1
5 2
4 6
3
Every element appears in exactly two terms. Thus, we have a simple linear combination of the elements, with coefficients of -2, 0 2. If the element is larger than both neighbors (e.g. 5), the coefficient is 2; if smaller than both neighbors (e.g. 1), it's -2; if between, the two abs operations cancel, and it's 0 (e.g. 4).
Lemma: the strength must be an even number.
Thus, the summation and some transformations can be examined easily enough with simple analysis. The largest number always has a coefficient of +2; the smallest always has a coefficient of -2.
You can find "close relative" permutations by finding interchangeable elements. For instance, you can always interchange the largest two elements (6 and 5) and/or the smallest two elements (1 and 2), without affecting the strength. For instance, 6 and 5 can be interchanged because they're strictly larger than their neighbors:
(6-2) + (6-3) + (5-1) + (5-4) =
(5-2) + (5-3) + (6-1) + (6-4) =
2*6 + 2*5 - 2 - 3 - 1 - 4
1 and 2 can be interchanged, even though they're adjacent, for a similar reason ... except that there are only three terms, one of which involves the pair:
(5-1) + (2-1) + (6-2) =
(5-2) + (2-1) + (6-1) =
5 + 6 - 2*1
Depending on the distribution of the set of numbers, there will likely be more direct ways to construct a ring with a given strength. Since we do not yet have an ordering defined on the permutations, we have no way to determine a "next" one. However, the simple one is to note that rotations and reflections of a given permutation will all have the same strength:
(1,2,6,3,4,5)
(2,6,3,4,5,1)
(6,3,4,5,1,2)
...
(5,4,3,6,2,1)
(4,3,6,2,1,5)
...
Does that get you moving?
Addition w.r.t. OP updates:
There are several trivially strength-invariant swaps available. I've already mentioned the two extreme pairs (6-5) and (1-2). You can also swap adjacent, consecutive numbers: that adds (4-5) and (3-4) in the above example. From simple algebraic properties, you can often identify a 2-element swap or 3-element rotation (respecting an increase in lexicographic position) that generates the next desired permutation. For instance:
(5, 6, 1, 3, 4, 2)
(5, 6, 1, 4, 2, 3) rotate 3, 4, 2
(5, 6, 1, 4, 3, 2) swap 2, 3
However, there are irruptions in the sequence that you'd be hard-pressed to find in this fashion. For instance, making the leap to change the first or second element is not so clean:
(5, 6, 3, 1, 4, 2)
(5, 6, 3, 2, 4, 1) swap 1, 2 -- easy
(6, 1, 2, 4, 5, 3) wholesale rearrangement --
hard to see that this is the next strength=14
I feel that finding these would require a set of algebraic rules that would find the simple moves and eliminate invalid moves (such as generating 563421 before the "wholesale rearrangement" just above). However, following these rules would often take more time than working through all permutations.
I'd love to find that I'm wrong on this last point. :-)
So I have an array 'a0' of size let's say 105, and now I have to make some changes in this array. The ith change could be calculated using a function f(ai-1) to give ai in O(1) time, Where aj denotes array 'a' after jth change has been made to it. Meaning that ai could be calculated if we know ai-1 in constant time. I know that I have to make 105 changes beforehand.
Now the problem asks me to answer large number of queries such as ai[p]-aj[q], where ax[y], represents yth element of the array after xth change has been made to the array a0.
Now if I had space of the order of 1010, I could easily solve this problem in O(1) by storing all the 105 arrays beforehand but I don't (generally) have that kind of space. And I could also answer these queries by each time generating ai and aj from scratch and answering the queries but I can't afford that kind of time complexity either, so I was wondering if I could monitor this problem using some data-structure.
EDIT: Example:
We define an array B= {1,3,1,4,2,6}, and we define aj as the array storing the frequency of ith number after jth element has been added to B. That is, a0={0,0,0,0,0,0} now a1={1,0,0,0,0,0}, a2={1,0,1,0,0,0}, a3={2,0,1,0,0,0} a4={2,0,1,1,0,0} a5={2,1,1,1,0,0} and a6={2,1,1,1,0,1}.
f(aj) just adds a an element to B and updates the value of aj-1.
Assume the number of changed elements per iteration is much smaller than the total number of elements. Store an array of lists, where the list elements are (i, new_value). For example if the full view is like this:
a0 = [3, 5, 1, 9]
a1 = [3, 5, 1, 8]
a2 = [1, 5, 1, 0]
We will store this:
c0 = [(0, 3), (2, 1)]
c1 = [(0, 5)]
c2 = [(0, 1)]
c3 = [(0, 9), (1, 8), (2, 0)]
Then for the query a2[0] - a1[3], we need only consult c0 and c3 (the two columns in the query). We can use binary search to locate the necessary indexes 2 and 1 (the keys for the binary search being the first elements of the tuples).
The query time is then O(log N) for the two binary searches, where N is the maximum number of changes to a single value in the array. The space is O(L + M), where L is the length of the original array and M is the total number of changes made.
If there is some a maximum number of states N, then checkpoints are a good way to go. For instance, if N=100,000, you might have:
c0 = [3, 5, 7, 1, ...]
c100 = [1, 4, 9, 8, ...]
c200 = [9, 7, 1, 2, ...]
...
c10000 = [1, 1, 4, 6, ...]
Now you have 1000 checkpoints. You can find the nearest checkpoint to an arbitrary state x in O(1) time and reconstruct x in at most 99 operations.
Riffing off of my comment on your question and John Zwinck's answer, if your mutating function f(*) is expensive and its effects are limited to only a few elements, then you could store the incremental changes. Doing so won't decrease the time complexity of the algorithm, but may reduce the run-time.
If you had unlimited space, you would just store all of the checkpoints. Since you do not, you'll have to balance the number of checkpoints against the incrementals appropriately. That will require some experimentation, probably centered around determining how expensive f(*) is and the extent of its effects.
Another option is to look at query behavior. If users tend to query the same or nearby locations repeatedly, you may be able to leverage an LRU (least-recently used) cache.
I have a sequential odd array starting at 3. So x = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13...}.
I am wondering if there is a quick way to find at what index the square of a number n is at. So if n was 5, I am looking for where 25 is in the array. Right now I have ((n) * (n - 1)) which I add to the current i index. Is there anything faster?
Your array is made of consecutive numbers and it's sorted, Because of this it forms a mathematical arithmetic progression with difference 1 and first element as 3, so at index i we have a[i]=i+3 and so i=a[i]-3.
So to find the index of the square of n let nsqr be n*n, nsqr index is simply nsqr-3, that's an O(1) algorithm.
To make it general whenever we have consecutive sorted numbers which start with a0 and differ by d, to find where is the square of n we do (nsqr-a0)/d.
Given an array like [15, 14, 12, 3, 10, 4, 2, 1]. How can I determine which elements are out of order and remove them (the number 3 in this case). I don't want to sort the list, but detect outliers and remove them.
Another example:
[13, 12, 4, 9, 8, 6, 7, 3, 2]
I want to be able to remove #4 and #7 so that I end up with:
[13, 12, 9, 8, 6, 3, 2]
There's also a problem that arises when you have this scenario:
[15, 13, 12, 7, 10, 5, 4, 3]
You could either remove 7 or 10 to make this array sorted.
In general, the problem I'm trying to solve, is that given a list of numerical readings (some could be off by quite a bit). I want the array to only include values that follow the general trendline and remove any outliers. I'm just wondering if there is a simple way to do this.
I would reduce your problem to the longest increasing (decreasing) subsequence problem.
https://en.wikipedia.org/wiki/Longest_increasing_subsequence
Since your sequence is nearly sorted, you are guaranteed to receive a satisfactory result (i.e. neatly following the trendline).
There exists a number of solutions to it; one of them is portrayed in the free book "Fundamentals of Computer Programming with C#" by Svetlin Nakov and Veselin Kolev; the problem is presented on page 257, exercise 6; solution is on page 260.
Taken from the book:
Write a program, which finds the maximal sequence of increasing elements in an array arr[n]. It is not necessary the elements to be consecutively placed. E.g.: {9, 6, 2, 7, 4, 7, 6, 5, 8, 4} -> {2, 4, 6, 8}.
Solution:
We can solve the problem with two nested loops and one more array len[0…n-1]. In the array len[i] we can keep the length of the longest consecutively increasing sequence, which starts somewhere in the array (it does not matter where exactly) and ends with the element arr[i]. Therefore len[0]=1, len[x] is the maximal sum max(1 + len[prev]), where prev < x and arr[prev] < arr[x]. Following the definition, we can calculate len[0…n-1] with two nested loops: the outer loop will iterate through the array from left to right with the loop variable x. The inner loop will iterate through the array from the start to position x-1 and searches for the element prev with maximal value of len[prev], where arr[prev] < arr[x]. After the search, we initialize len[x] with 1 + the biggest found value of len[prev] or with 1, if such a value is not found.
The described algorithm finds the lengths of all maximal ascending sequences, which end at each of the elements. The biggest one of these values is the length of the longest increasing sequence. If we need to find the elements themselves, which compose that longest sequence, we can start from the element, where the sequence ends (at index x), we can print it and we can search for a previous element (prev). By definition prev < x and len[x] = 1 + len[prev] so we can find prev with a for-loop from 1 to x-1. After that we can repeat the same for x=prev. By finding and printing the previous element (prev) many times until it exists, we can find the elements, which compose the longest sequence in reversed order (from the last to the first).
A simple algorithm which has been described by higuaro can help you to generate a correct sequence:
For each element at index i , if a[i] < a[i + 1], we can simply remove that element a[i].
for(int i = 0; i < size; i++)
while(a[i] < a[i + 1]){
remove a[i];
i--;
}
However, this approach cannot guarantee that the number of removed element is minimum. For example, for this sequence [10, 9, 8, 100, 1, 0], remove 100 will be optimal, instead of remove 8, then 9 then 10.
To find the minimum number of element to be removed, we notice that we need to find the longest decreasing sub sequence, which is similar to the classic longest increasing sub sequence whose solution has been described here
Give an array of integers.
For example a = {1,2,20,19}
Let two disjoint sub-arrays be {1,2} and {20,19}. There are 5 such permutations in which '1' always comes before '2' and '20' always comes before '19' and such are:
{1, 2, 20, 19}
{1, 20, 2, 19}
{1, 20, 19, 2}
{20, 1, 19, 2}
{20, 19, 1, 2}
My question is:
Given an array, a[1...n+m] of size=n+m. Find the number of permutations in which relative order of elements in two sub-arrays a[1..n] and a[n+1..n+m] remains the same.
In your example it will be 6 permutations. You've missed the {20,1,2,19}.
It is a pure math(combinatorics) question. The question is equivalent to -
find the number of all possible solutions of the equation :
x0+x1+....+xn = m
The answer is defined by the formula - (n+m)!/(m!n!)
For example in your case it will be n=m=2 and the answer is 4!/2!2! = 6
Suppose you have m+n empty positions. You have to fill these positions such that the relative ordering is correct.
Choose n positions. The number of ways to choose n positions is (m+n)!/n!m!.
Now there is only one way to fill the elements of the subarray1 to those n locations such that the relative ordering is preserved.
The rest m positions are empty. There is only one way to place the elements from subarray2 to the rest m positions such that relative ordering is preserved.
Hence the final answer becomes (m+n)!/m!n!.