We are given a grid of size N * N where each element A[i][j] is calculated by this equation (i + j) ^ 2 + (j-i) * 10^5.
We need to find the Kth min element in optimized way.
Constraints :
1 <= number of test cases <= 20
1 <= N <= 5*10^4
1 <= k <= N^2
How to solve this problem in an efficient way ?
The problem that you are trying to solve (finding kth smallest element in an unordered array) is called the selection problem. There are many ways to solve this problem, and one of the best known ways is the quick select algorithm.
You can solve this problem in O(N log N) time. Note that that is sublinear in the size of the matrix, which is N*N. Of course you should never actually construct the matrix.
First, it helps to see what the values in the matrix looks like:
Note that over the possible range of matrix sizes, the smallest element is always at (i,j) = (N-1,0).
The largest element will be either (0,N-1) or (N-1,N-1), depending on the size of the matrix.
Consider the elements on the line from the smallest to largest. If you pick any one of these elements, then you can trace the contour to find the number of <= elements in O(N) time.
Furthermore, the elements on this line are always monotonically increasing from smallest to largest, so do a binary search on this line of elements, to find the largest one such that the number of <= elements is < k. At O(N) time per test, this takes O(N log N) all together.
Let's say the element you discover has value x, and the number of elements <= x is r, with r < k. Next trace the contour for the next higher element on the line, call its value y, and make list of all the values v such that x < v <= y. There will be O(N) elements in this list, and this takes only O(N) time.
Finally, just use sorting or quickselect to pick the (k-r)th element from this list. Again this takes at mostO(N log N) time.
Related
What would be the time complexity of partitioning an array in two and finding the minimum element overall?
Is it O(n) or O(log n)?
The complexity of dividing an (unsorted) array into 2 sorted partitions is O(NlogN).
Once you have two sorted partitions, it is O(1) to find the smallest element in either ... and hence both partitions.
(The smallest element of a sorted partition is the first one.)
Time Complexity for Partitioned Array
If an array A is already divided in two sorted partitions P1 and P2, where P1 is distributed along the indexes of A 0 <= i < k and P2 along the indexes k <= i < n with k an arbitrary index within the range 0 <= k < n.
Then, you know that the smallest element of both partitions is their first. Accessing both partition's first element has a time complexity of O(1) and comparing the two smallest values retrieved has again a time complexity of O(1).
So, the overall complexity of finding the minimum value in an array divided into two sorted partitions is O(1).
Time Complexity for Array to Partition
Instead, if the given array A has to be sorted in two sorted partitions (because this is a requirement) and then you need to find its minimum element. Then you need to divide your array into two partitions with an arbitrary index k, sort the two partitions with the most efficient sorting algorithm, which has complexity O(n log n), and then applying the same logic exposed above in finding the minimum element.
For any given value of k, with k 0 <= k < n, we would have to apply the sorting algorithm twice (on both partitions). However, since the additive property of Complexity Computation states that the addition of two complexities of the same order is still equal to the same complexity, then for example for k = n/2 we would have that: O(n/2 log n/2) + O(n/2 log n/2) still produces O(n log n). More in general O(k log k) + O((n-k) log (n-k)) with 0 <= k < n and n => ∞, which will still give us O(n log n) due to the constant factors property. Finally, we need to account to this complexity the constant complexity, O(1) of finding the minimum element among the two partitions, which will still give us O(n log n).
In conclusion, the overall complexity for dividing an array A in two partitions P1 and P2 and finding the minimum element overall is O(n log n).
I ran into an interview question recently.
We have m*n matrix such that each row is in non-decreasing order (sorted with distinct elements). design an algorithm on order O(m (log m+ log n)) to find k-th smallest element on this matrix (just one element as k-th smallest element).
I think this is not possible so search on Google and find this link and another solution and this answer to a similar question.
I think as follows:
Put the median of all rows into an array and we find the median of this array in O(m) and called it pivot
We find the rank of this element in O(m log n). i.e: in each row how many elements are lower than the pivot found in step (1).
By comparing k and "rank of the pivot" we can know that in each row works on the right half or left half. (reduce to m*n/2 matrix.)
But the time complexity of this algorithm is O(m * log^2 n). What is the algorithm that can works on O(m (log n + log m))? Is there any idea?
m - rows
n - columns
Is it compulsory that you want a solution with O(m (log m+ log n)) Complexity?
I Can Think of a Solution with Complexity O(k * log-m) with extra space of O(m)
You can use a modified PriorityQueue (heap) DataStructure for this complexity
class PQObject {
int value; // PQ sorting happens on this int..
int m; // And m and n are positions.
int n;
}
You can just put all the values from the first column to the Priority Queue and Start popping until the kth smallest element
Every time you pop re-insert the next value of the row using m and n in the popped object.
Ultimately the problem comes down to find the kth smallest element in M sorted arrays.
If only the smaller partitioned array is being called how is the larger one sorted? I only see code to change the position of b if done recursively (QS called in if and else statement).
public static void QS(int[] b, int h, int k) {
int h1= h; int k1= k;
// invariant b[h..k] is sorted if b[h1..k1] is sorted
while (b[h1..k1] has more than 1 element) {
int j= partition(b, h1, k1);
// b[h1..j-1] <= b[j] <= b[j+1..k1]
if (b[h1..j-1] smaller than b[j+1..k1])
QS(b, h, j-1); h1= j+1;
else
QS(b, j+1, k1); k1= j-1;
}
}
That is some hard to read psuedo-code. This might be a bit easier to understand:
QuickSort(b[], low, hi)
while the range low..hi contains more than 1 element
1: Pick a random pivot 'j' from the array
2: Re-order the array so that all elements less than the pivot are in
b[low..j-1], and all elements greater than the pivot are in b[j+1..hi]
3: Call quicksort on the side with less elements, and update the range to
exclude the sorted side
Roughly half of the values will be less than the pivot, and half of the values will be greater than the pivot. This means that after step 3, the size of the range low..hi has roughly halved. Thus, it takes log|N| iterations before the range contains only one element.
It's hard to explain this bit, but see how step 3 only calls QuickSort on one half of the array? It's because the remainder of the while-loop sorts the other half. The function could easily be re-written as the following:
QuickSort(b[], low, hi)
if the range low..hi contains more than 1 element
1: Pick a random pivot 'j' from the array
2: Re-order the array so that all elements less than the pivot are in
b[low..j-1], and all elements greater than the pivot are in b[j+1..hi]
3: Call quicksort on both sides
The while-loop has been replaced by an if statement and a second recursive call. I hope from here that you can see the complexity is roughly N log|N|.
Edit
So how does the while-loop sort the remaining elements? After step 3, the range has been updated to exclude the smaller half, because we just sorted it with a call to QuickSort. This means that the range now only contains the larger half - the unsorted elements. So we repeat steps 1 - 3 on these unsorted elements, and update the range again.
The number of unsorted elements gets smaller and smaller with every iteration, and eventually we will be left with only one unsorted element. But of course, one element on its own is sorted, so at this point we know we have sorted every element in the array.
Note after the recursive call to QS, h1 is is updated if b[h1..] was smaller than b[j+1..] and k1 is updated if if b[h1..] was greater or equal to b[j+1..] .
There's a bug in the code, the first call after the if should be QS(b, h1, j-1);
Logarithmic space usage is referring to the stack space used by quicksort due to recursion. In the example code, only the smaller partition is sorted with a recursive call, then the code loops back to split up the larger partition into two parts, and again, only use a recursive call for the smaller part of the now split up larger partition.
Link to articles:
http://en.wikipedia.org/wiki/Quicksort#Optimizations
http://blogs.msdn.microsoft.com/devdev/2006/01/18/efficient-selection-and-partial-sorting-based-on-quicksort
I'm not sure about the reference to tail recursion, since the code includes an actual loop instead of using tail recursion. Tail recursion would look like a recursive call on the last line to be executed in a function, where a compiler can optimize it into a loop.
Hi I am trying to solve this problem from IEEEXtreme 2014:
You are given N integers that are arranged circularly. There are N ways to pick consecutive subsequences of length M (M < N). For any such subsequence we can find the “K”-value of that subsequence. “K”-value for a given subsequence is the K-th smallest number in that subsequence. Given the array of N, find the smallest K-value of all possible subsequences. For example N=5 M=3 K=2 and the array 1 5 3 4 2 give the result 2.
My approach is first I create a sorted array list which inserts the new input in the correct position. I add the first M integers into the list. Record the K-th smallest value. Then I keep removing the oldest integer and adding the next integer into the list and comparing the new K-th value with the old one. This is my sorted array list.
class SortedArrayList extends ArrayList {
public void insertSorted(int value) {
for (int i = size()-1; i >= 0; i--){
if( value - (Integer)get(i)>=0){
add(i+1,new Integer(value));
return;
}
}
add(0,new Integer(value));
}
}
I think this brute-force method is not efficient but not able to come up with any ideas yet. Do you know any better solutions for this ? Thanks.
Here is a more efficient solution:
Let's get rid of circularity to keep things simpler. We can do it by appending the given array to itself.
We can assume that all numbers in the input are unique. If it is not the case, we may use a pair (element, position) instead of each element.
Let's sort the given array. Now we will use the binary search over the answer(that is, the position of the k-th smallest element among all subarrays in the sorted global array).
How to check that a fixed candidate x is at least as large as the k-th smallest number? Let's mark all positions of the numbers less than or equal to x with 1 and the rest with 0. Now we just need to check if there is a subarray of length M that contains at least k ones. We can do it in linear time using rolling sums.
The time complexity is: O(N log N) for sorting the input + O(N log N) for binary search over the answer(there are O(log N) checks and each of them is done in linear time as described in 4.). Thus, the total time complexity is O(N log N).
P.S. I can think of several other solutions with the same time complexity, but this one seems to be the simplest one to implement(it does not require any custom data structures).
More elegant solution for the problem with the circular array would be to simply use modulo. So, if you're just looking for a solution for simulating a circular array, i would suggest something like this:
int n = somevalue;//the startingpoint of the subsequence
int m = someothervalue;//the index in the subsequence
int absolute_index = (n + m) % N;
where N is the total number of elements in the sequence.
Next step towards more efficiency would be to store the index of the k-th value. This way, you'd only have to calculate a new K-Value every M-th step (worst case) and simply compare it to one new value per every other step.
But i'll leave that to you ;)
Question: Given a sorted array A find all possible difference of elements from A.
My solution:
for (int i=0; i<n-1; ++i) {
for (int j=i+1; j<n; ++j) {
System.out.println(Math.abs(ai-aj));
}
}
Sure, it's O(n^2), but I don't over count things at all. I looked online and I found this: http://www.careercup.com/question?id=9111881. It says you can't do better, but at an interview I was told you can do O(n). Which is right?
A first thought is that you aren't using the fact that the array is sorted. Let's assume it's in increasing order (decreasing can be handled analogously).
We can also use the fact that the differences telescope (i>j):
a_i - a_j = (a_i - a_(i-1)) + (a_(i-1) - a_(i-2)) + ... + (a_(j+1) - a_j)
Now build a new sequence, call it s, that has the simple difference, meaning (a_i - a_(i-1)). This takes only one pass (O(n)) to do, and you may as well skip over repeats, meaning skip a_i if a_i = a_(i+1).
All possible differences a_i-a_j with i>j are of the form s_i + s_(i+1) + ... + s_(j+1). So maybe if you count that as having found them, then you did it in O(n) time. To print them, however, may take as many as n(n-1)/2 calls, and that's definitely O(n^2).
For example for an array with the elements {21, 22, ..., 2n} there are n⋅(n-1)/2 possible differences, and no two of them are equal. So there are O(n2) differences.
Since you have to enumerate all of them, you also need at least O(n2) time.
sorted or unsorted doesn't matter, if you have to calculate each difference there is no way to do it in less then n^2,
the question was asked wrong, or you just do O(n) and then print 42 the other N times :D
You can get another counter-example by assuming the array contents are random integers before sorting. Then the chance that two differences, Ai - Aj vs Ak - Al, or even Ai - Aj vs Aj - Ak, are the same is too small for there to be only O(n) distinct differences Ai - Aj.
Given that, the question to your interviewer is to explain the special circumstances that allow an O(n) solution. One possibility is that the array values are all numbers in the range 0..n, because in this case the maximum absolute difference is only n.
I can do this in O(n lg n) but not O(n). Represent the array contents by an array of size n+1 with element i set to 1 where there is a value i in the array. Then use FFT to convolve the array with itself - there is a difference Ai - Aj = k where the kth element of the convolution is non-zero.
If the interviewer is fond of theoretical games, perhaps he was thinking of using a table of inputs and results? Any problem with a limit on the size of the input, and that has a known solution, can be solved by table lookup. Given that you have first created and stored that table, which might be large.
So if the array size is limited, the problem can be solved by table lookup, which (given some assumptions) can even be done in constant time. Granted, even for a maximum array size of two (assuming 32-bit integers) the table will not fit in a normal computer's memory, or on the disks. For larger max sizes of the array, you're into "won't fit in the known universe" size. But, theoretically, it can be done.
(But in reality, I think that Jens Gustedt's comment is more likely.)
Yes you can surely do that its a little tricky method.
to find differances in O(n) you will need to use BitSet(C++) or any similar Data Structure in respective language.
Initialize two bitset say A and B
You can do as follows:
For each iteration through array:
1--store consecutive differance in BitSet A
2--LeftShift B
3--store consecutive differance in BitSet B
4--take A=A or B
for example I have given code-
Here N is Size of array
for (int i=1;i<N;i++){
int diff = arr[i]-arr[i-1];
A[diff]=1;
B<<=diff;
B[diff]=1;
A=A | B;
}
Bits in A which are 1 will be the differances.
First of all the array need to be sorted
lets think a sorted array ar = {1,2,3,4}
so what we were doing at the O(n^2)
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++) sum+=abs(ar[i]-ar[j]);
if we do the operations here elaborately then it will look like below
when i = 0 | sum = sum + {(2-1)+(3-1)+(4-1)}
when i = 1 | sum = sum + {(3-2)+(4-2)}
when i = 2 | sum = sum + {(4-3)}
if we write them all
sum = ( -1-1-1) + (2+ -2-2) + (3+3 -3) + (4+4+4 )
we can see that
the number at index 0 is added to the sum for 0 time and substracted from the sum for 3 time.
the number at index 1 is added to the sum for 1 time and substracted from the sum for 2 time.
the number at index 2 is added to the sum for 2 time and substracted from the sum for 1 time.
the number at index 3 is added to the sum for 3 time and substracted from the sum for 0 time.
so for we can say that,
the number at index i will be added to the sum for i time
and will be substracted from the sum for (n-i)-1 time
Then the generalized expression for
each element will be
sum = sum + (i*a[i]) – ((n-i)-1)*a[i];