Binary-search with duplicate elements in array - java

I want find if there is a single element in a list of duplicate elements.
For this code
private static int findDuplicate(int array[]) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = array[mid];
if (midVal == mid)
low = mid + 1;
else
high = mid - 1;
}
return high;
}
It find the duplicate number but I want to find only the single number
in the duplicate and sorted array.
For example, given this int[] input:
[1,1,2,2,3,3,4,5,5]
Output would be '4'.
Or this int[] input:
[1,1,2,2,3,4,4,5,5,6,6]
Output would be '3'.
In this int[] input:
[1,1,2,7,7,9,9]
Output would be '2'.
I'm working in Java now but any language or psuedo-code is fine.
I know the obvious traversal at O(n) linear time, but I'm trying to see if this is possible via binary search at O(log n) time.
The elements are sorted and only duplicate twice!
I know the way with simple loop but I want to do it by binary search.

Consider each pair of 2 consecutive elements: (the pairs with 2 elements different are highlighted) (note that there's a stray element at the end)
(1 1) (2 2) (3 3) (4 5) (5 6) (6 7) (7 8) (8)
Observe that the only non-duplicated element will make the corresponding pair and all the later pairs have different values, the pairs before that have the same value.
So just binary search for the index of the different pair.
This algorithm also don't require that the list is sorted, only that there's exactly one element which appears once, and all other elements appear twice, in consecutive indices.
Special case: if the last element is the unique one, then all the pairs will have equal values.

Every pair of same values will be like below in terms of indices:
(0,1),
(2,3),
(4,5)
(6,7)
etc. You can clearly see that if index is even, check with next element for similarity. If index is odd, you can check with previous value for similarity.
If this symmetry is broken, you can move towards left side or if everything is ok, keep moving right.
Pseudocode(not tested):
low = 0,high = arr.length - 1
while low <= high:
mid = (low + high) / 2
if mid == 0 || mid == arr.length - 1 || arr[mid] != arr[mid-1] and arr[mid] != arr[mid + 1]: // if they are corner values or both left and right values are different, you are done
return arr[mid]
if(mid % 2 == 0):
if arr[mid + 1] != arr[mid]: // check with next index since even for symmetry
high = mid
else:
low = mid + 2
else:
if arr[mid - 1] != arr[mid]: // check with prev index since odd for symmetry
high = mid
else:
low = mid + 1
return -1

Related

Using a Variant of BinarySearch to Find the Maximum in a Bitonic Array

Here is my code, where a is the array to find the maximum of (each element is distinct). From my perspective, if a[mid] is less than a[mid-1] then the position of the maximum should be in the range of [lo, mid-1]. However, when I implement my idea, the program is endless. The solution is to use [lo, mid] as the next iteration.
My question is: Why shouldn't I use mid-1 instead of mid in Line 9?
First edit: Some people ask why didn't I just sort and choose the first element? Since the problem is to find a key in a bitonic array (where elements ascend first then descend). My solution is to find the maximum of the array, separate it into two parts and respectively use BinarySearch to find the key. If I sort the array I will destroy the original order.
Second edit: add more code in detail and the expected output.
public static int getMaxIndex(int[] a) {
int hi = a.length - 1;
int lo = 0;
while (lo < hi && a[lo] <= a[lo+1]) {
int mid = lo + (hi - lo) / 2;
if (a[mid] > a[mid-1]) {
lo = mid;
} else {
hi = mid - 1; // Should be mid, not mid-1, why?
}
}
return lo;
}
public static void main(String[] args) {
int[] a = {1, 2, 3, 5, 7, 9, 8, 6, 4}; // Bitonic array
System.out.println(getMaxIndex(a)); // Should be 5
}
bitonic array
The numbers are strictly increasing and after an index, the numbers are strictly decreasing
eg: [15, 20, 26, 5, 1]
If the array contains only unique elements, then maximum can be found using following conditions
iterate while left index < right index
compute middle index (towards left incase no single middle index)
if the value at middle is smaller than next element, then move towards right
else move left towards left
arr[mid] < arr[mid + 1] will never throw out of bounds exception as left < right invariant is maintained on the loop. hence mid(index) will always be lesser than right(index) and hence there is atleast one index after mid
int left = 0, right = arr.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
right = mid;
}
}
return arr[left]; // or arr[right]
15 20 26 5 1
l=0, r=4 l m r
m=2
a[m] > a[m+1] l r
so, r=m
l=0, r=2 l m r
m=1
a[m] < a[r+1] l,r
m=l+1
Now exit while loop l == r and return value at l or r
Analysis of OP's code
A simple reproducible example is [1, 2] - this will cause lo to be stuck to same index and causes infinite loop.
Any dataset that reduces to lo + 1 == hi and arr[lo] < arr[hi] will set mid to lo (lo + (hi - lo) / 2 will be lo) and hence the assignment lo = mid causes an infinite loop
The problem you had was that you were not always changing mid. In your example, at one point lo is 4 and pointing to 7 in the array while hi is 5 and points to 9. In the situation where lo and hi are just 1 apart, mid is set to lo. Here you are comparing a[mid] > a[mid-1]. Problem 1, mid-1 is out of range and in rare cases gives an ArrayIndexOutOfBoundsException. Second, if the condition is true, you set lo to mid, which is the value it already had. You are getting nowhere. You are in an infinite loop.
I tried your method with
System.out.println(getMaxIndex(new int[] { 3 , 8 })); // Expecting 1
I got java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 2
The solution is in the answer by Horse.
Here, the word bitonic means, array is sorted in increasing order, and after some point (may be) it starting to decrease.
Likewise, you have to find the pivot point where array is starting to decrease (if it is exist), if you can able to find the point, that's it, this pivotal point is your answer.
so i am attaching some input/output sequence to make it more clear:
{1, 2, 3, 5, 7, 9, 8, 6, 4}; --> should return 5 (index at which element is maximum)
{15, 20, 26, 5, 1} --> should return 2 (index at which element is maximum)
{0, 1, 2, 3} --> should return 3 (index at which element is maximum)
now you have to modify your code like following:
public static int getMaxIndex(int[] arr) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if(mid == 0 || mid == arr.length-1) {
// if no such pivotal point exist in sequence/array
return mid;
}else if(arr[mid] > arr[mid+1] && arr[mid] > arr[mid-1]){
// it's the pivotal point, where element at left side smaller and element at right side too
return mid;
}
if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
right = mid;
}
}
return -1;
}

How to find the Kth largest difference in int[]?

I have an Algorithm question.
For example, there is an int[] array like [1,5,4,3,7,2].
I want to find the kth largest difference in this array like :
array[i] - array[j] = kth largest difference
(index i must smaller than j and array[i] must larger than array[j]).
The output is return the j in this question.
My current idea:
I can build a int[][] to store all the difference in the array.
Then sorting them and find the kth larget difference.
But time complexity is O(n^2).
Are there better solutions?
You could run 2 separate methods that finds the max and min of the corresponding arrays then find the difference.
OR
You can use your method of creating a new array that finds the difference of every single value THEN find the max of that array and output that.
Then use Array sort() method to reorder an array and print out the values of max differences when called by index+1
Example in Python
results = []
a = [1,5,4,3,7,2]
a_new = [(1,0), (5,1), (4,2), (3,3), (7,4), (2,5)] #(5,1) -> 5:value and 1:index
sort a_new by value # e.g. mergesort O(nlogn)
start_index = 0
end_index = len(a_new) - 1
i = -1
j = -1
diff = 0
while true: # sequential search
if(a_new[start_index][1] < a_new[end_index][1]): #compare i and j
tmp_diff = a_new[end_index][0] - a_new[start_index][0]
i = start_index
j = end_index
diff = tmp_diff
results.append((I,j,diff)) #add a tuple in results_list
end_index -= 1
else: # a_new[start_index][1] > a_new[end_index][1]
start_index += 1
if start_index == end_index: break
sort results by diff and return results[k-1]
I hope this help. I can't check typing error.
My Idea is: max difference is -> max_possible_element_value - min_element_value
Sample:
results = []
a_new = [(1,0), (2,5), (3,3), (4,2), (5,1), (7,4)]
start_index = 0
end_index = len(a_new) - 1
i = -1
j = -1
diff = 0
while True:
if(a_new[start_index][1] < a_new[end_index][1]):
i = a_new[start_index][1]
j = a_new[end_index][1]
diff = a_new[end_index][0] - a_new[start_index][0]
results.append((i, j, diff))
end_index -= 1
else:
start_index -= -1
if start_index == end_index: break
print(results)
Result:
[(0, 4, 6), (0, 1, 4), (0, 2, 3), (0, 3, 2), (0, 5, 1)]
you can sort the result array then get kth diff.
Pseudocode-wise, it could go this way :
You can sort the current array descending, then start your calculation like so :
diffList = {}
calculate(array,k) :
if (k<=0) OR (array.length < 2) OR (k > 2^(array.length-1))
return nothing // whatever behavior you want (exception or null Integer whatever suits you)
else
return kthLargest(k, 0 , array.length-1, array)
end if
kthLargest(count, upperBound, lowerBound, array) :
if count = 0
if upperBound != lowerBound
return max(array[upperBound]-array[lowerBound], max(sortDesc(diffList)))
else
return max(sort(diffList))
end if
else if upperBound = lowerBound
sortDesc(diffList)
return diffList[count]
else
topDiff = array[upperBound]-array[upperBound+1]
botDiff = array[lowerBound-1]-array[lowerbound]
if(topDiff > botDiff)
add botDiff to diffList
return kthLargest(count-1,upperBound,lowerBound-1,array)
else
add topDiff to diffList
return kthLargest(count-1,upperBound+1,lowerBound,array)
end if
end if
Call calculate(array,k) and you're set.
This basically keeps track of a 'discarded pile' of differences while iterating and reducing bounds to always have your final largest difference be the current bounds' difference or a potential better value in that discarded pile.
Both sorts (omitted for brevity) should make this O(n log n).
You can substitute arrays for the most convenient collections, and unwrap this into an iterative solution also.
Corrections appreciated!
It can be done in complexity O( N * logN + N * logValMax ). First lets sort the array. After that we can build a function countSmallerDiffs( x ) which counts how many differences smaller or equal to x are in the array, this function has complexity O( N ) using two pointers. After that we can binary search the result in range minVal-maxVal. We need to find p such that satisfies countSmallerDiffs( p ) <= k < countSmallerDiffs( p + 1 ). The answer will be p.
Hope this helps you out! Good luck!

Looking through different combinations through matrix using just visited int variable?

I am looking at this topcoder problem here:
http://community.topcoder.com/tc?module=ProblemDetail&rd=4725&pm=2288
Under the java section there is this code :
public class KiloManX {
boolean ddd = false;
int[] s2ia(String s) {
int[] r = new int[s.length()];
for (int i = 0; i < s.length(); i++) {
r[i] = s.charAt(i) - '0' ;
}
return r;
}
public int leastShots(String[] damageChart, int[] bossHealth) {
int i, j, k;
int n = damageChart.length;
int[][] dc = new int[n][];
int[] cost = new int[1 << n];
for (i = 0; i < n; i++) {
dc[i] = s2ia(damageChart[i]) ;
}
for (i = 1; i < 1 << n; i++) {
cost[i] = 65536 * 30000;
for (j = 0; j < n; j++) {
int pre = i - (1 << j);
if ((i & (1 << j)) != 0) {
cost[i] = Math.min(cost[i], cost[pre] + bossHealth[j]) ;
for (k = 0; k < n; k++) {
if ((i & (1 << k)) != 0 && k != j && dc[k][j] > 0) {
cost[i] = Math.min(cost[i],
cost[pre] + (bossHealth[j] + dc[k][j] - 1) / dc[k][j]);
}
}
}
}
}
return cost[(1 << n) - 1] ;
}
static void pp(Object o) {
System.out.println(o);
}
}
I am trying to understand what he is been done. So what I understand is :
i - keeps track of the visited nodes somehow(this is the most baffling part of the code)
j - is the monster we want to defeat
k - is the previous monster's weapon we are using to defeat j
dc is the input array of string into a matrix
cost, keep cost at each step, some sort of dynamic programming? I don't understand how cost[1 << n] can give the result?
What I understand is they are going through all the possible sets / combinations. What I am baffled by (even after executing and starring at this for more than a week) is:
how do they keep track of all the combinations?
I understand pre - is the cost of the previous monster defeated (i.e. how much cost we incurred there), but I don't understand how you get it from just (i - 1 << j).
I have executed the program(debugger), stared at it for more than a week, and tried to decode it, but I am baffled by the bit-manipulation part of the code. Can someone please shed light on this?
cost, keep cost at each step, some sort of dynamic programming?
They are partial costs, yes, but characterizing them as per-step costs misses the most important significance of the indices into this array. More below.
I don't understand how cost[1 << n] can give the result?
That doesn't give any result by itself, of course. It just declares an array with 2n elements.
how do they keep track of all the combinations?
See below. This is closely related to why the cost array is declared the size it is.
I understand pre - is the cost of the previous monster defeated (i.e. how much cost we incurred there), but I don't understand how you get it from just (i - 1 << j).
Surely pre is not itself a cost. It is, however, used conditionally as an index into the cost array. Now consider the condition:
if ((i & (1 << j)) != 0) {
The expression i & (1 << j) tests whether bit j of the value of i is set. When it is, i - (1 << j) (i.e. pre) evaluates to the the result of turning off bit j of the value of i. That should clue you in that the indices of cost are bit masks. The size of that array (1 << n) is another clue: it is the number of distinct n-bit bitmasks.
The trick here is a relatively common one, and a good one to know. Suppose you have a set of N objects, and you want somehow to represent all of its subsets (== all the distinct combinations of its elements). Each subset is characterized by whether each of the N objects is an element or not. You can represent that as N numbers, each either 0 or 1 -- i.e. N bits. Now suppose you string those bits together into N-bit numbers. Every integer from 0 (inclusive) to 2N (exclusive) has a distinct pattern of its least-significant N bits, so each corresponds to different subset.
The code presented uses exactly this sort of correspondence to encode the different subsets of the set of bosses as different indices into the cost array -- which answers your other question of how it keeps track of combinations. Given one such index i that represents a subset containing boss j, the index i - (1 << j) represents the set obtained from it by removing boss j.
Roughly speaking, then, the program proceeds by optimizing the cost of each non-empty subset by checking all the ways to form it from a subset with one element fewer. (1 << n) - 1 is the index corresponding to the whole set, so at the end, that element of cost contains the overall optimized value.

Binary search recursive number of calls?

So I was wondering, in my book, recursive binary search is implemented as follows:
private static int bin(int[] arr, int low, int high, int target){
counter++; //ignore this, it was to count how many calls this function invocated
if(low > high) return -1;
else{
int mid = (low+high) / 2;
if(target == arr[mid]) return mid;
else if(target < arr[mid]) return bin(arr, low, mid-1, target);
else return bin(arr, mid + 1, high, target);
}
}
And it says that "If n, the number of elements, is a power of 2, express n as a power of 2... Case 3: The key is not in the array, and its value lies between a[0] and a[n-1]. Here the number of comparisons to determine that the key is not in the array is equal to the exponent. There will be one fewer comparison than in the worst case."
But when I sat down and found the number of function calls using an array {1,2,3,4,5,6,7,9} and key of 8, the number of calls was 4. The book says the number of COMPARISONS is 3 (which is excluding the 3rd line I am guessing?), but I'm pretty sure the number of function calls is 4. I also generalized this to an iterative implementation of binary search and generalized that the number of iterations, OR recursive function calls, is always floor(log base 2 ( n ) ) + 1.
Can explain what's going on here?
Only 3 target == arr[mid] comparisons are made. On the fourth iteration the base case if(low > high) is reached so the comparison is never made. As you stated: "Here the number of comparisons to determine that the key is not in the array is equal to the exponent." You are correct in that we are not dealing with the comparison statement on line 3. We are only concerned with the comparison statement for our target value.
Let's look at the iterations until either of the 2 base cases are reached.
Binary search for 8 in array {1,2,3,4,5,6,7,9}
First iteration:
low = 0
high = 7
mid = 3
arr[mid] = 4
(target == arr[mid]) == false
Second iteration:
low = 4
high = 7
mid = 5
arr[mid] = 6
(target == arr[mid]) == false
Third iteration:
low = 7
high = 7
mid = 7
arr[mid] = 7
(target == arr[mid]) == false
Forth iteration:
low = 8
high = 7
low > high == true
Also, the Big O notation is O(log n). The + 1 is considered insignificant in Big O and therefore not counted. Please see this list on Wikipedia for order of Big O functions from fastest to slowest.

Binary search 1/4 modification

My task is to write 1/4 - 3/4 binary search algorithm modification wherein the first element compared, when searching for an item in the list, is the 'pivot' element which is at a distance of 1/4th from
one end of the list(assuming the end chosen is the start of the 'remaining'
list). If there is no match ('pivot' element is not equal to the search key) and
if the part of the list that should be examined further for the search is 1/4th
part of the list, continue with the same strategy. Whenever the part of the
list that should be examined further for the search is of size 3/4th, switch to
a binary search once and return to the 1/4th-3/4th strategy.
My code is here, but it doesnt work, and i dont know even if i am doing it right:
public static int ThreeFour(int[] Array,int item)
{
int counter =0;
int high=Array.length-1;
int low=0;
int pivot = 0;
boolean split = true;
boolean last =true;
while(high >= low) {
if(split){
pivot = (high+low)/4;
last=true;}
else
{ pivot = (high+low)/2;
split=true;
last=false;
}
if(Array[pivot] == item)
{ counter++;
System.out.println("Pivot"+pivot);
return counter;
}
if(Array[pivot] < item) {
low = pivot + 1;
counter++;
}
if(Array[pivot] > item) {
high = pivot - 1;
counter++;
if (last)
split=false;
}
}
return 0;
}
It doesnt work, maybe there is a simplier strategy to do that? The hardest part is to make it remember that it already splited in half once:/
Your formula to determine the pivot is wrong for the 3/4 split. If you want to split an interval between low and high at some point c with 0 <= c <=1, you get:
pivot = low + c * (high - low)
= (1 - c) * low + c * high
This wil give you low for c == 0, highfor c == 1 and for your 3/4 split:
pivot = 0.75 * low + 0.25 * high
or, with integer arithmetic:
pivot = (3 * low + high) / 4
In particular, the factors for low and high should sum up to 1.
I also think that your function has a logic error: You return the recursion depth, which has no meaning to the array. You should return the pivot, i.e. the array index at which the item is found. That also means that you can't return 0 on failure, because that's a valid array index. Return an illegal index like -1 to indicate that the item wasn't found.

Categories