I recently read the article from PEG Wiki about the convex hull trick. Surprisingly, at the end of the article I read that we can achieve a fully dynamic variant of the trick (meaning that there are no conditions of applicability) if we store the lines in a std::set. Although I have understood the approach mentioned, I always fail when I try to implement it.
In other words, there is an array A of size n, where each array element contains two positive integers ai and bi.
There are Q queries where each query can be one of two types:
1) Given a positive integer x, find max (aix + bi) for all i from 1 to n
2) Update values of ai and bi for some i.
Value to be updated will be in non-decreasing order i.e. ai1>=ai2 and bi1>=bi2 for Q >= i1 > i2 >= 1.
Update Part can be performed using by deleting previous line and adding a new line. I am looking both update and query part for amortized (log n) complexity in Java
Related
I saw this method in a book, to do binary search, but I can't understand how it is working no matter how I try. Can someone explain to me exactly how it is working?
the book's explanation did not help :
The idea is to make jumps and slow the speed when we get closer to the
target element.
The variables k and b contain the position in the array and the jump
length. If the array contains the element x , the position of x will
be in the variable k after the search. The time complexity of the
algorithm is O (log n ), because the code in the while loop is
performed at most twice for each jump length.
what I don't get is that how is k iterating in the array? How can we make sure that it will not jump over the target's index? I tried tracing some runs of this program with sample values but couldn't figure out the pattern that k is following to find whether target x exists in the array or not.
int k = 1;
for (int b = n/2; b >= 1; b /= 2) {
while (k+b <= n && t[k+b] <= x) k += b;
}
if (t[k] == x) {} // x was found at index k
note: I do understand clearly the "common binary search algorithm" (the one that uses start, middle, and end indices )
b are the length of the jumps of your current position. As you can see, b starts as n/2 and is divided by 2 at each step up until it reaches 1.
Now, For each b, remember that b is divided by 2 at each step in the for loop, we run a while loop where we add b to to our current position, which is k. We add b to k checking for 2 conditions: k+b is less than n (to make sure we don't go out of bounds), and t[k+b] is less than x, which we are searching.
This effectively means that for each b, we add b to k up until where it would go over the value we are seeking. At this point, the while loop breaks and we divide b to approach slower to the target hoping we don't go over it.
The final b is just one, to make sure we don't miss x if it is just the next element after the position of k.
Look at it this way, a car is racing towards a goal. At first the car is going maximum speed, as it nears the target, it gradually decelerates up until it reaches the target.
The difference with traditional binary search, which makes it a little counter intuitive, is that in traditional binary search, we go over the target and then come back and go over again and in each iteration we decrease the steps that we take back and forth. In this algorithm, we only go forwards (never over the target), but we continuously decrease the length of the steps by dividing b.
This is the pseudo code that i want to calculate time complexity ,i think it is a binary search algorithm but i fail when calculating the complexity because it is reducing logarithamic.
USE variables half-array,found,middle element
SET half-array=initial array;
SET found=True;
Boolean SearchArray(half-array)
find middle element in half-array;
Compare search key with middle element;
IF middle element==search key THEN
SET found=True;
ELSE
IF search key< middle element THEN
SET half-array=lower half of initial array;
ELSE
SET half-array=upper half of initial array;
SearchArray(half-array)
It looks like you are running this method recursively, and with each iteration you are reducing the number of elements being searched by half. This is going to be a logarithmic reduction, i.e. O(log n).
Since you are reducing your elements by half each time, you need to determine how many executions will be needed to reduce it to a single element, which this previous answer provides a proof or if you are a more visual person, you can use the following diagram from this response:
Yes,It is indeed a binary search algorithm.The reason why it is called a 'binary' search is because,if you would have noticed,after each iteration,your problem space is reduced by roughly half (I say roughly because of the floor function).
So now,to find the complexity,we have to devise a recurrence relation,which we can use to determine the worst-case time complexity of binary-search.
Let T(n) denote the number of comparisons binary search does for n elements.In the worst case,no element is found.Also,to make our analysis easier,assume that n is a power of 2.
BINARY SEARCH:
When there is a single element,there is only one check,hence T(1) = 1.
It calculates the middle entry then compares it with our key.If it is equal to the key,it returns the index,otherwise it halves the range by updating upper and lower bounds such that n/2 elements are in the range.
We then check only one of the two halves,and this is done recursively until a single element is left.
Hence,we get the recurrence relation:
T(n) = T(n/2) + 1
Using the Master Theorem,we get the time complexity to be T(n) ∈ Θ(log n)
Also refer : Master Theorem
You are correct in saying that this algorithm is Binary Search (compare your pseudo code to the pseudo code on this Wikipedia page: Binary Search)
That being the case, this algorithm has a worst case time complexity of O(log n), where n is the number of elements in the given array. This is due to the fact that in every recursive call where you don't find the target element, you divide the array in half.
This reduction process is logarithmic because at the end of this algorithm, you will have reduced the list to a single element by dividing the number of elements that still need to be checked by 2 - the number of times you do that is roughly equivalent (see below) to the number of times you would have to multiply 2 by itself to obtain a number equal to the size of the given array.
*I say roughly above because the number of recursive calls made is always going to be an integral value, whereas the power you would have to raise 2 to will not be an integer if the size of the given list is not a power of two.
I am currently working on this coding problem for class.
Given a sorted array of n distinct values as well as a target value T, determine in O(n) time whether or not there exist two distinct values in the array that sum to T. (For example, if the array contained 3, 5, 6, 7, and 9 and T = 14, then the method you are to write should return true, since 5+9 = 14. It should return false if for the same array of values T = 17.)
So, initially, I just wrote the problem with a nested linear search approach which obviously results in a O(n^2) runtime to establish a baseline to simplify from, however, I have only been able to, so far, simplify it to O(n log(n)). I did this by creating a new array made up of the differences of the Target - array[i] and then comparing the new array to the original array using a binary search nested within a loop that linearly goes up the new array.
I am not asking for an answer but rather a hint at where to look to simplify my code. I feel like the fact that the array is sorted is important in getting it down to O(n) but not sure how to go about doing it.
Thanks for your time!
Imagine you have two pointers (s, e) wich set on start and end of you array.
If you will move them in opposite direction (with specific algorithm) and look at the summ of elements you will see that moving one pointer increase summ and moving other decrease.
Onli thing you need is find balance.
If it doesnt help. Ask for next tip.
Some tips/steps:
1 - Start the iteration by the array[i], which is the nearest lower value from T
2 - Move another pointer to the array[0]
3 - Sum both values and compare with T
4 - If bigger or if lower, do appropriate moving in the pointers and repeat the step 3
A Hint:
Something like Binary Search, start with middle (compare with middle)
we have startindex = 0, endindex = N-1
while(some condition){
middleindex = endindex - startindex / 2, middle = array[middleindex]
if T - array[middleindex] > middle, startindex = middleindex
if T - array[middleindex] < middle, endindex = middleindex
}
It will do the task in O(log(n)) :D
I have an int[] array that contains values with the following properties:
They are sorted
They are unique (no duplicates)
They are in a known range [0..MAX)
MAX is typically quite a lot larger than the length of the array (say 10-100x)
Sometimes the numbers are evenly distributed across the range, but at other times there are quite long sequences of consecutive numbers. I estimate it is about 50/50 between the two cases.
Given this list, I want to efficiently find the index of a specific value in the array (or if the value is not present, find the next higher value).
I've already implemented a straight binary search with interval bisection that works fairly well, but I have a suspicion that the nature/distribution of the data can be exploited to converge to a solution faster.
I'm interested in optimising the average case search time, but it is important that the worst case is never worse than O(log n) as the arrays are sometimes very large.
Question: it is possible to do much better than a plain binary search in the average case?
EDIT (to clarify additional questions / comments)
The constant in O(log n) definitely matters. In fact assuming that better algorithmic complexity than O(log n) isn't possible, the constant is probably the only thing that matters.....
It's often a one-off search, so while preprocessing is possible it's probably not going to be worth it.
This is in the comments and should be an answer. It's a joint effort, so I'm making it a CW answer:
You may want to look at an interpolation search. In the worst case, they can be worse than O(log n) and so if that's a hard requirement, this wouldn't apply. But if your interpolation is decent, depending on the data distribution an interpolation search can beat a straight binary.
To know, you'd have to implement the interpolation search with a reasonably smart interpolation algorithm, and then run several representative data sets through both to see whether the interpolation or the binary is better suited. I'd think it'd be one of the two, but I'm not au fait with truly cutting edge searching algorithms.
Let's name the interval x here and z the searched number.
Since you expect the values to be evenly distributed, you can use interpolation search. This is similar to binary search, but splits the index range at start + ((z - x[start]) * (end - start)) / (x[end] - x[start]).
To get a running time of O(log n) you have to do combine interpolation search with binary search (do step from binary search and step from interpolation search alternating):
public int search(int[] values, int z) {
int start = 0;
int end = values.length-1;
if (values[0] == z)
return 0;
else if (values[end] == z) {
return end;
}
boolean interpolation = true;
while (start < end) {
int mid;
if (interpolation) {
mid = start + ((z - values[start]) * (end - start)) / (values[end] - values[start]);
} else {
mid = (end-start) / 2;
}
int v = values[mid];
if (v == z)
return mid;
else if (v > z)
end = mid;
else
start = mid;
interpolation = !interpolation;
}
return -1;
}
Since every second iteration of the while loop does a step in binary search, it uses at most twice the number of iterations a binary search would use (O(log n)). Since every second step is a step from interpolation search, it the algorithm should reduce the intervall size fast, if the input has the desired properties.
If int[] is
sorted
have unique values
you know the range (in advance)
Than instead of searching why not to save the value at its index.
Say the number is 243 than save the value in int[243] = 243.
That way searching will be easy and faster. Only thing left is to find out next higher value.
I have one solution.
you are saying array can be
1)numbers are evenly distributed across the range
2)there are quite long sequences of consecutive numbers.
So, first we start a simple test to make sure whether its of type1 or type2.
To test for type 1,
lenght =array.length;
range = array[length-1] - array[0];
Now consider the values of array at
{ length(1/5),length(2/5),length(3/5),length(4/5)},
If the array distribution is of type 1, then we approximately know what must be the value at array[i], so we check whether at those above 4 positions whether they are close to known values if its equal distribution.
If they are close, then its equal distribution and so we can easily find any element in array.If we can't find element based on above approach, we consider it is of type 2.
If above test Fails then it is of type 2, which means in the array there are few places where long sequences of consecutive numbers is present.
so, we solve it in terms like binary search.Explanation is below
*we first search in the middle of the array,(say at length/2, index as i)
left =0,right=length;
BEGIN:
i=(left+right)/2;
case a.1: our search number is greater than array[i]
left=i;
*Now we check at that position is there any long consecutive sequence is present, i.e array[i],array[i+1],array[i+2] are consecutive ints.
case a.1.1: (If they are in consecutive),
as they are consecutive ,and the sequence might be long, we directly search at particular index based on our search integer value.
For example, if our search int is 10, and sequence is 5,6,7,8,9,10,11 15,100,103,
and array[i]=5, then we directly search at array[i+10-5],
If we find our search int, return it, else continue from case a.2 only [because it will obviously less than it] by setting right as
right=(array[i+10-5])
case a.1.2, if they are not consecutive
continue from BEGIN;
case a.2: our search number is less than array[i],
*case a.2 is exactly similar to a.1
*similarly check is there any back sequence , i.e array[i-2],array[i-1],array[i] are in sequence,
If they are in consecutive sequence , search back to exact value as we did in case a.1.1
If they are not consecutive, repeat similar to case a.1.2.
case a.3, it is our search int,
then return it.
HOPE THIS helps
Do you know any way to get k-th element of m-element combination in O(1)? Expected solution should work for any size of input data and any m value.
Let me explain this problem by example (python code):
>>> import itertools
>>> data = ['a', 'b', 'c', 'd']
>>> k = 2
>>> m = 3
>>> result = [''.join(el) for el in itertools.combinations(data, m)]
>>> print result
['abc', 'abd', 'acd', 'bcd']
>>> print result[k-1]
abd
For a given data the k-th (2-nd in this example) element of m-element combination is abd. Is it possible to that value (abd) without creating the whole combinatory list?
I'am asking because I have data of ~1,000,000 characters and it is impossible to create full m-character-length combinatory list to get k-th element.
The solution can be pseudo code, or a link the page describing this problem (unfortunately, I didn't find one).
Thanks!
http://en.wikipedia.org/wiki/Permutation#Numbering_permutations
Basically, express the index in the factorial number system, and use its digits as a selection from the original sequence (without replacement).
Not necessarily O(1), but the following should be very fast:
Take the original combinations algorithm:
def combinations(elems, m):
#The k-th element depends on what order you use for
#the combinations. Assuming it looks something like this...
if m == 0:
return [[]]
else:
combs = []
for e in elems:
combs += combinations(remove(e,elems), m-1)
For n initial elements and m combination length, we have n!/(n-m)!m! total combinations. We can use this fact to skip directly to our desired combination:
def kth_comb(elems, m, k):
#High level pseudo code
#Untested and probably full of errors
if m == 0:
return []
else:
combs_per_set = ncombs(len(elems) - 1, m-1)
i = k / combs_per_set
k = k % combs_per_set
x = elems[i]
return x + kth_comb(remove(x,elems), m-1, k)
first calculate r = !n/(!m*!(n-m)) with n the amount of elements
then floor(r/k) is the index of the first element in the result,
remove it (shift everything following to the left)
do m--, n-- and k = r%k
and repeat until m is 0 (hint when k is 0 just copy the following chars to the result)
I have written a class to handle common functions for working with the binomial coefficient, which is the type of problem that your problem appears to fall under. It performs the following tasks:
Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters. This method makes solving this type of problem quite trivial.
Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle. My paper talks about this. I believe I am the first to discover and publish this technique, but I could be wrong.
Converts the index in a sorted binomial coefficient table to the corresponding K-indexes. I believe it too is faster than other published techniques.
Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.
The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to perform the 4 above methods. Accessor methods are provided to access the table.
There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.
To read about this class and download the code, see Tablizing The Binomial Coeffieicent.
It should not be hard to convert this class to Java, Python, or C++.