You are given an array of N positive integers, A1,A2,…,An. You have to answer Q queries. Each query consists of two integers L and K. For each query I have to tell the Kth element which is larger than or equal to L in the array when all such elements are listed according to increasing order of their indices.
Example A = 22,44,12,16,14,88,25,49
Query 1: L = 3 K = 4
Since all elements are greater than 3. So we list the whole array i.e. 22,44,12,16,14,88,25,49. 4th element among these elements is 16
Query 2: L = 19 K = 5
Listed elements 22,44,88,25,49. 5th element among these is 49.
What I have done: for each query iterate over the whole array and check the Kth element which is larger than or equal to L. Complexity : O(Q*N)
What I require: O(Q*logN) complexity.
Constraints : 1<=Q<=10^5 1<=N<=10^5 1<=Ai<=10^5
One possible way to solve this task is to use immutable binary (RB) tree.
First you need to sort your array in ascending order, storing original indices of the elements next to the elements.
Traverse array in reverse (descending) order, adding elements one by one to immutable binary tree. Key in the tree is original index of the element. Tree is immutable, so by adding element I mean constructing new tree with added element. Save the tree created on each step near the corresponding element (the element that was last added to the tree).
Having these trees constructed for each element you can do your queries in O(log N) time.
Query:
First, perform a binary search for L in sorted array (O(log N)) for the element that is bigger than L. You'll find the element and corresponding tree of indices of the elements that are bigger than L. In this tree you can find K-th largest index in O(log N) time.
The whole algorithm will take O(N log N + Q log N) time. I don't believe that it is possible to do better (as sorting the original array seems to be inevitable).
The key of this approach is using immutable binary tree. This structure shares the properties of mutable binary tree, such as insertion and search in O(log N), while staying immutable. When you add element to such tree, the previous version of the tree is preserved, only nodes that are different from the previous "version" of the tree are recreated. Usually it's O(log N) nodes. Thus creating N trees from elements of your array will require O(N log N) time and O(N log N) space.
You can use immutable RB tree implementation in Scala as the reference.
Related
I have an array A of size N. All elements are positive integers. In one step, I can add two adjacent elements and replace them with their sum. That said, the array size reduces by 1. Now I need to make all the elements same by performing minimum number of steps.
For example: A = [1,2,3,2,1,3].
Step 1: Merge index 0 and 1 ==> A = [3,3,2,1,3]
Step 2: Merge index 2 and 3 (of new array) ==> [3,3,3,3]
Hence number of steps are 2.
I couldn't think of a straight solution, so tried a recursive approach by merging all indices one by one and returning the min level I can get when either array size is 1 or all elements are equal.
Below is the code I tried:
# Checks if all the elements are same or not
def check(A):
if len(set(A)) == 1:
return True
return False
# Recursive function to find min steps
def min_steps(N,A,level):
# If all are equal return the level
if N == 1 or check(A):
return level
# Initialize min variable
mn = float('+inf')
# Try merging all one by one and recur
for i in range(N-1):
temp = A[:]
temp[i]+=temp[i+1]
temp.pop(i+1)
mn = min(mn, min_steps(N-1,temp, level+1))
return mn
This solution has complexity of O(N^N). I want to reduce it to polynomial time near to O(N^2) or O(N^3). Can anyone help me modify this solution or tell me if I am missing something?
Combining any k adjacent pairs of elements (even if they include elements formed from previous combining steps) leaves exactly n-k elements in total, each of which we can map back to the contiguous subarray of the original problem that constitutes the elements that were added together to form it. So, this problem is equivalent to partitioning the array into the largest possible number of contiguous subarrays such that all subarrays have the same sum: Any adjacent pair of elements within the same subarray can be combined into a single element, and this process repeated within the subarray with adjacent pairs chosen in any order, until all elements have been combined into a single element.
So, if there are n elements and they sum to T, then a simple O(nT) algorithm is:
For i from 0 to T:
Try partitioning the elements into subarrays each having sum i. This amounts to scanning along the array, greedily adding the current element to the current subarray if the sum of elements in the current subarray is strictly < i. When we reach a total of exactly i, the current subarray ends and a new subarray (initially having sum 0) begins. If adding the current element takes us above the target of i, or if we run out of elements before reaching the target, stop this scan and try the next outer loop iteration (value of i). OTOH if we get to the end, having formed k subarrays in the process, stop and report n-k as the optimal (minimum possible) number of combining moves.
A small speedup would be to only try target i values that evenly divide T.
EDIT: To improve the time complexity from O(nT) to O(n^2), it suffices to only try target i values corresponding to sums of prefixes of the array (since there must be a subarray containing the first element, and this subarray can only have such a sum).
Suppose we want to perform external sort and have M number of blocks sorted, where each block contains k comparable items such that n = Mk. k in this case also refers to the maximum number of items you can fit into memory for sorting, and n is the total number of items to sort.
Then using the merge function in merge sort, each element will have to be compared against all other elements from other blocks, which gives me O(M) comparison for one element. Since we have to do this for all elements, we will have O(M * Mk) = O(M^2 * k) = O(nM) time complexity.
This seems to be linear at first, but suppose in the worst case we can only fit 1 item into memory. So we have M=n blocks, and the time complexity is O(n^2) directly. How does the merging gives you linear time in external sort?
Also, in the case where k = 1, how is the sorting even feasible when there cannot be any comparisons done?
Make priority queue based? for example, on binary heap, fill it with current items (or their indexes) from every block, and extract top item at every step.
Extracting takes O(log(M)) per output element, so full merging is O(n*log(M))
For your artificial example: O(n*log(n))
Let A, an array of numbers. We need to create an array B such that B[i] = min(A[i],...,A[i+sqrt(n)].
Why is the tightest upper bound for the creation of B is O(nlogn)?
I was actually given a list of options:
O(sqrt(n)*logn)
O(n/logn)
O(n*logn)
O(nlog(n)^2)
O(n*sqrt(n))
O(n^2)
The answer is O(nlogn), since it is the lowest yet not sublinear option.
It can be done in O(nlogn) by maintaining a sorted DS (self balancing BST for example) of size sqrt(n), and iteratively remove and add elements to it (while running a sliding window on the array).
Each iteration is done in O(log(sqrt(n)) = O(1/2*log(n)) = O(logn), and there are O(n) iterations, so total of O(nlogn).
This disqualifies all "higher" alternatives, and all "lower" alternatives are sub-linear, and you cannot create the array in sublinear time.
Given an array , each element is one more or one less than its preceding element .find an element in it.(better than O(n) approach)
I have a solution for this but I have no way to tell formally if it is the correct solution:
Let us assume we have to find n.
From the given index, find the distance to n; d = |a[0] - n|
The desired element will be atleast d elements apart and jump d elements
repeat above till d = 0
Yes, your approach will work.
If you can only increase / decrease by one at each following index, there's no way a value at an index closer than d could be a distance d from the current value. So there's no way you can skip over the target value. And, unless the value is found, the distance will always be greater than 0, thus you'll keep moving right. Thus, if the value exists, you'll find it.
No, you can't do better than O(n) in the worst case.
Consider an array 1,2,1,2,1,2,1,2,1,2,1,2 and you're looking for 0. Any of the 2's can be changed to a 0 without having to change any of the other values, thus we have to look at all the 2's and there are n/2 = O(n) 2's.
Prepocessing can help here.
Find Minimum and Maximum element of array in O(n) time complexity.
If element to be queried is between Minimum and Maximum of array, then that element is present in array, else that element is not present in that array.So any query will take O(1) time. If that array is queried multiple times, than amortized time complexity will be lesser that O(n).
I want to sort a list of entries and then select a subset (page) of that sorted list. For example; I have 10.000 items and want to have items 101 until 200.
A naive approach would be to first sort all 10.000 items and then select the page; it would mean that items 1 - 100 and 201 - 10.000 are all unnecessarily fully sorted.
Is there an existing algorithm that will only fully sort the items in the page and stops further sorting of an entry once it is clear it is not in the page? source code in C would be great, but descriptions would also be ok
Suppose you want items p through q out of n. While sorting would cost O(n·log n) time, the operation you mention can be done in O(n) time (so long as q-p « n) as follows: Apply an O(n)-time method to find the pᵗʰ and qᵗʰ values. Then select only items with values from p to q, in time O(n+k) if k=q-p, or about O(n) time, and sort those items in time O(k·log k), which is about O(1), for net time O(n) if k is O(1).
Suppose the page you want starts with the nth "smallest" element (or largest or whatever ordinal scale you prefer). Then you need to divide your partial sorting algorithm into two steps:
Find the nth element
Sort elements {n, n+1, ..., n+s} (where s is the page size)
Quicksort is a sorting algorithm that can be conveniently modified to suit your needs. Basically, it works as follows:
Given: a list L of ordinally related elements.
If L contains exactly one element, return L.
Choose a pivot element p from L at random.
Divide L into two sets: A and B such that A contains all the elements from L which are smaller than p and B contains all the elements from L which are larger.
Apply the algorithm recursively to A and B to obtain the sorted sublists A' and B'.
Return the list A || p || B, where || denotes appending lists or elements.
What you want to do in step #1, is run Quicksort until you've found the nth element. So step #1 will look like this:
Given: a list L of ordinally related elements, a page offset n and a page size s.
Choose a pivot element p from L at random.
Divide L into A and B.
If the size of A, #A = n-1, then return p || B.
If #A < n-1, then apply the algorithm recursively for L' = B and n' = n - #A
If #A > n-1, then apply the algorithm recursively for L' = A and n' = n
This algorithm returns an unsorted list of elements starting with the nth element. Next, run Quicksort on this list but keep ignoring B unless #A < s. At the end, you should have a list of s sorted elements which are larger than n elements from the original list but not larger than n+1 elements from the original list.
The term you want to research is partial sorting. There is likely to be an implementation of it in C or any sufficiently popular language.