How does this binary search works? - java

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.

Related

Understanding a particular solution to 'Minimum Swaps to Group All 1's Together 2nd' problem

I am looking at the LeetCode problem 2134. Minimum Swaps to Group All 1's Together II:
A swap is defined as taking two distinct positions in an array and swapping the values in them.
A circular array is defined as an array where we consider the first element and the last element to be adjacent.
Given a binary circular array nums, return the minimum number of swaps required to group all 1's present in the array together at any location.
I am trying to study how other people came up with solutions of their own. I came across this particular one, but I don't understand the logic:
class Solution {
public int minSwaps(int[] nums) {
// number of ones
int cntones=Arrays.stream(nums).sum();
// worst case answer
int rslt=nums.length;
// position lft and figure better value for min/rslt
int holes = 0;
for(int i=0;i<cntones;i++) {
if(nums[i]==0)
holes++;
}
// better value for rslt from lft to rgt
// up to index of cntones.
rslt = Math.min(rslt, holes);
// they have a test case with one element
// and that trips up if you dont do modulo
int rgt=cntones % nums.length;
for(int lft=0;lft<nums.length;lft++) {
rslt=Math.min(rslt,holes);
if(nums[lft]!=nums[rgt])
if(nums[rgt]==1)
holes--;
else
holes++;
rgt=(rgt+1)%nums.length;
}
return rslt;
}
}
Why is the worst case, the length of the input array?
I'm thinking wait, wouldn't the worst case be something like [0,1,0,1,0,1...] where 0's and 1's are alternating? Can you give me an example?
I suppose #of holes can potentially be a possible solution in some cases, from counting 0's in a fixed length (the number of total 1's) of a window but because I do not understand the worst case, rslt from question #1, below line stumps me as well.
// better value for rslt from lft to rgt
// up to index of cntones.
rslt = Math.min(rslt, holes);
About the modulo below, I don't think cntones can ever be bigger than nums.length, in turn which will result in 0 all the time? I'm thinking for the case with one element, you'd have to check whether that one element is 0 or 1. How does below line cover that edge case?
// they have a test case with one element
// and that trips up if you dont do modulo
int rgt=cntones % nums.length;
Due to #1~#3 the last for loop makes no sense to me...
Why is the worst case, the length of the input array?
First note that a swap is only useful when it swaps a 0 with 1. Secondly, it makes no sense to swap the same digit a second time, as the result of such double swap could have been achieved with a single swap. So we can say that an upper limit for the number of swaps is the number of 0-digits or number of 1-digits (which ever is the least). In fact, this is an overestimation, because at least one 1-digit should be able to stay unmoved. But let's ignore that for now. To reach that worst case, there should be as many 1 as 0 digits, so then we have half of the length as worst case. Of course, by initialising with a value that is greater than that (like the length) we do no harm.
The example of alternating digits would be resolved by keeping half of those 1-digits unmoved, and moving the remaining 1-digits in the holes between them. So that means we have a number of swaps that is equal to about one fourth of the length of the array.
below line stumps me as well.
rslt = Math.min(rslt, holes);
As you said, there is a window moving over the circular array, which represents the final situation where all 1-digits should end up. So it sets the target to work towards. Obviously, the 1-digits that are already within that window don't need to be swapped. Each 0-digit inside that window has to be swapped with a 1-digit that is currently outside that window. Doing that will reach the target, and so the number of swaps for reaching that particular target window is equal to the number of holes (0-digits) inside that window.
As that exercise is done for each possible window, we are interested to find the best position of the window, i.e. the one where the number of holes (swaps) is minimised. That is what this line of code is doing. rslt is the minimum "so far" and holes is the fresh value we have for the current window. If that is less, then rslt should be updated to it. That's what happens in this statement.
About the modulo below, I don't think cntones can ever be bigger than nums.length, in turn which will result in 0 all the time? I'm thinking for the case with one element, you'd have to check whether that one element is 0 or 1. How does below line cover that edge case?
int rgt=cntones % nums.length;
That modulo only serves for the case that cntones is equal to nums.length. You are right that it will never exceed it. But the case where it is equal is possible (when the input only has 1-digits). And as rgt is going to be used as an index, it should not be equal to nums.length as that is an undefined slot in the array.
Due to #1~#3 the last for loop makes no sense to me...
It should be clear from the above details. That loop moves the window with one step at a time, and keeps the variable holes updated incrementally. Of course, we could have decided to count the number of holes from scratch in each window, but that would be a waste of time. As we go from one window to the next, we only lose one digit on the left and gain one on the right, so we can just update holes with that information and know how many holes there are in the current window -- the one that starts at lft and runs (circular) to rgt. In case the digit that we lose at the left is the same as the one we gain at the right, we obviously didn't change the number of holes. Where they are different, we either win or lose one hole in comparison with the previous window.

Dynamic Programming - Rod Cutting Problem with maximum cuts and actual solution

So I'm trying to write code for a modified version of the rod cutting problem. The link gives a good intuition of the problem. However, I want to modify the code to not only actually return the solution, i.e. what cuts give the optimal solution, but also limit the number of cuts to a maximum of k.
For proof of concept, I'm trying to create an algorithm to achieve this. The following is what I have so far, I think it successfully returns the actual solution, however, I can't figure out how to limit the maximum to k.
let r[0..n] be a new array
r[0] = 0
for j = 1 to n
q = -1
for i = 1 to j
for k = 0 to n-1
q = Math.max(q[n][k], p[i] + q[n-i-1][k-1]);
r[j] = q
return r[n]
Please do not provide with actual code in your answers, I want to implement that myself, I just need help tweaking my algorithm to give the correct solution.
Update 1: I am already able to find optimal solution for a maximum of k cuts by adding a second dimension to my array. This is shown in the above code.
As you say, you already have the optimal solution, this answer includes only how to retrace the exact solution (cuts made at each step).
Store the candidate cut for length = n and maximum cuts = k
For this, you simply need a 2-d array (say, visit[n][k]) to store the cut made that gets the maximum solution to q[n][k]. In terms of pseudo code and recurrence relations, it will look like the following.
for each value of i:
q[n][k] = q[n][k-1]
visit[n][k] = -1
if q[n][k] < p[i] + q[n-i-1][k-1]:
q[n][k] = p[i] + q[n-i-1][k-1]
visit[n][k] = i
Explanation
It is possible that we don't have a cut that maximizes the solution. In this case, we initialize visit[n][k] = -1.
Every time, we have a candidate to cut the rod of length n at length=i+1, ie. we could get a better price by a cut, we will store the respective cut in another 2-d array.
Reconstruct the solution
Using this 2-d array (visit[n][k]), to back trace the exact cuts, you can use the following pseudo code (I am deliberately avoiding code since you mentioned you don't need it).
cuts = []
while k > 0:
i = visit[n][k]
if i != -1
// If there is a cut
cuts.push(i + 1)
n = n - i - 1
k = k - 1
Explanation
We iterate from k to 0.
Every time, when visit[n][k] is not -1, ie. it is optimal to cut somewhere, we reassign n after making the cut, ie. n = n - i - 1 and store the resultant cut in the array cuts.
Finally, cuts will contain the exact cuts that led to the optimal solution.
Please note that the pseudo code present in your question is slightly incorrect in terms of variables used in the recurrence relation. q is used both to store the DP 2-d array as well as an integer -1. j is not used in the bottom-up DP at all and is replaced with constant n. q[j][k] is uninitialized. However, the general idea is correct.

Convex Hull Optimization Java

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

Sorted Array Distinct Values Sum to Target

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

Pseudocode/Java Mystery Algorithm

I have an algorithm, and I want to figure it what it does. I'm sure some of you can just look at this and tell me what it does, but I've been looking at it for half an hour and I'm still not sure. It just gets messy when I try to play with it. What are your techniques for breaking down an algoritm like this? How do I analyze stuff like this and know whats going on?
My guess is its sorting the numbers from smallest to biggest, but I'm not too sure.
1. mystery(a1 , a2 , . . . an : array of real numbers)
2. k = 1
3. bk = a1
4. for i = 2 to n
5. c = 0
6. for j = 1 to i − 1
7. c = aj + c
8. if (ai ≥ c)
9. k = k + 1
10. bk = ai
11. return b1 , b2 , . . . , bk
Here's an equivalent I tried to write in Java, but I'm not sure if I translated properly:
public int[] foo(int[] a) {
int k=1;
int nSize=10;
int[] b=new int[nSize];
b[k]=a[1];
for (int i=2;i<a.length;){
int c=0;
for (int j=1;j<i-1;)
c=a[j]+c;
if (a[i]>=c){
k=k+1;
b[k]=a[i];
Google never ceases to amaze, due on the 29th I take it? ;)
A Java translation is a good idea, once operational you'll be able to step through it to see exactly what the algorithm does if you're having problems visualizing it.
A few pointers: the psuedo code has arrays indexed 1 through n, Java's arrays are indexed 0 through length - 1. Your loops need to be modified to suit this. Also you've left the increments off your loops - i++, j++.
Making b magic constant sized isn't a good idea either - looking at the pseudo code we can see it's written to at most n - 1 times, so that would be a good starting point for its size. You can resize it to fit at the end.
Final tip, the algorithm's O(n2) timed. This is easy to determine - outer for loop runs n times, inner for loop n / 2 times, for total running time of (n * (n / 2)). The n * n dominates, which is what Big O is concerned with, making this an O(n2) algorithm.
The easiest way is to take a sample but small set of numbers and work it on paper. In your case let's take number a[] = {3,6,1,19,2}. Now we need to step through your algorithm:
Initialization:
i = 2
b[1] = 3
After Iteration 1:
i = 3
b[2] = 6
After Iteration 2:
i = 4
b[2] = 6
After Iteration 3:
i = 5
b[3] = 19
After Iteration 4:
i = 6
b[3] = 19
Result b[] = {3,6,19}
You probably can guess what it is doing.
Your code is pretty close to the pseudo code, but these are a few errors:
Your for loops are missing the increment rules: i++, j++
Java arrays are 0 based, not 1 based, so you should initialize k=0, a[0], i=1, e.t.c.
Also, this isn't sorting, more of a filtering - you get some of the elements, but in the same order.
How do I analyze stuff like this and know whats going on?
The basic technique for something like this is to hand execute it with a pencil and paper.
A more advanced technique is to decompose the code into parts, figure out what the parts do and then mentally reassemble it. (The trick is picking the boundaries for decomposing. That takes practice.)
Once you get better at it, you will start to be able to "read" the pseudo-code ... though this example is probably a bit too gnarly for most coders to handle like that.
When converting to java, be careful with array indexes, as this pseudocode seems to imply a 1-based index.
From static analysis:
a is the input and doesn't change
b is the output
k appears to be a pointer to an element of b, that will only increment in certain circumstances (so we can think of k = k+1 as meaning "the next time we write to b, we're going to write to the next element")
what does the loop in lines 6-7 accomplish? So what's the value of c?
using the previous answer then, when is line 8 true?
since lines 9-10 are only executed when line 8 is true, what does that say about the elements in the output?
Then you can start to sanity check your answer:
will all the elements of the output be set?
try running through the psuedocode with an input like [1,2,3,4] -- what would you expect the output to be?
def funct(*a)
sum = 0
a.select {|el| (el >= sum).tap { sum += el }}
end
Srsly? Who invents those homework questions?
By the way: since this is doing both a scan and a filter at the same time, and the filter depends on the scan, which language has the necessary features to express this succinctly in such a way that the sequence is only traversed once?

Categories