Java arrays.binary search multiple matches? - java

I need to find all elements in sorted array with Arrays.binarySearch method. I want to iterate binary search in lowerbound = pos + 1 (pos is previous match), but binarySearch is not guaranteed to return first match (min match index)?
How can I make this?

You can easily use the result of binarySearch to get all the matches :
long[] sortedArr = ...
int index = Arrays.binarySearch (sortedArr, value);
int first = index;
int last = index;
if (index >= 0) {
while (first > 0 && sortedArr[first-1] == value)
first--;
while (last < sortedArr.length - 1 && sortedArr[last+1] == value)
last++;
}
After you run this code, the indices between first and last (inclusive) are all the indices that contain the searched value.

Related

Search method that finds an element by cutting an array in halves (Java)

I'm working on an assignment.
What I must create is a method that searches for an specific int in an array. It is assumed that the array is already sorted from lowest to highest number. But the condition is that it must search by cutting said array by half and checking in which of the halves the target number is in, then cut said half in half again and so on so on.
We were asked not to use recursive methods as well.
This is the code I came up with but I fail to see my mistake, any help to understand the problem better is more than appreciated!!!
public static boolean SearchInHalf(int[] array, int targetint)
{
int fin = array[array.length-1];
int init = array[0];
int range = fin-init;
if ( targetint>array[array.length-1] || targetint< array[0])
{
return false;
}
while (range>=2)
{
int half = array[range/2];
if (targetint>half)
{
init = half;
range = fin-init;
half = array[range/2];
}
else if (targetint<half)
{
fin = half;
range = fin-init;
half = array[range/2];
}
else if (targetint==half || targetint==fin || targetint==init)
{
return true;
}
}
return false;
}
Your problem is known as the "Binary Search". For binary search to work, the elements in the array must already be ordered (which is your case, let's assume ascending). The binary search first compares the key with the element in the middle of the array:
If the key is less than the middle element, you need to continue to search for the key only in the first half of the array.
If the key is greater than the middle element, you need to continue to search for the key only in the second half of the array.
If the key is equal to the middle element, the search ends with a match.
So binary search method eliminates at least half of the array after each comparison. Assuming you will call this method in your static main function:
public static int binarySearch(int[] list, int key) {
int low = 0;
int high = list.length - 1;
while(high >= low) { //search array until there is a single element left
int mid = (low + high) / 2; //mark middle index
if (key < list[mid]) //if key is smaller than the middle element..
high = mid - 1; //new high is the middle element
else if (key == list[mid]) //if key=middle element --> voila!
return mid; //returns the index of searched element if it is in your array
else
low = mid + 1; //if key is greater than the middle element new low is middle element
}
return –low - 1; //high < low, key not found
}
Solved it like this:
while (true) {
if (targetint>array[array.length-1] || targetint<array[0])
return false;
int middleInt = array[Math.round(array.length/2)];
if (middleInt == targetint) {
return true;
} else if (targetint<middleInt) {
int[] firstHalf = new int[array.length/2];
System.arraycopy(array, 0, firstHalf, 0, firstHalf.length);
array = firstHalf;
} else if (targetint>middleInt) {
int[] secondHalf = new int[array.length/2];
System.arraycopy(array, array.length/2, secondHalf, 0, secondHalf.length);
array = secondHalf;
} else if(array.length == 1)
return false;
}

binary search to return more than one index JAVA

I have the array {1,2,3,4,4,4,5}
I want my function return index of 4.
for example : 4 found at location 4,5,6
public void binarySearch(int value){
sort(); // sorting the array
int index=-1;
int lower=0;
int upper=count-1;
while(lower<=upper){
int middle=(lower+upper)/2;
if(value==array[middle]){
index=middle;
System.out.println(value+ " found at location "+(index+1));
break;
}
else if(value<array[middle]){
upper=middle-1;
}
else lower=middle+1;
}
}
It's not too hard. We know that because the list is sorted, all of our indexes are going to be contiguous (next to one another). So once we've found one, we just have to traverse the list in both directions to find out what other indexes also match.
public static void binarySearch(int value){
sort();
int index = -1;
int lower = 0;
int upper = array.length - 1;
while(lower <= upper){
// The same as your code
}
// Create a list of indexes
final List<Integer> indexes = new LinkedList<>();
// Add the one we already found
indexes.add(index);
// Iterate upwards until we hit the end or a different value
int current = index + 1;
while (current < array.length && array[current] == value)
{
indexes.add(current);
current++;
}
// Iterate downwards until we hit the start or a different value
current = index - 1;
while (current >= 0 && array[current] == value)
{
indexes.add(current);
current--;
}
// Sort the indexes (do we care?)
Collections.sort(indexes);
for (int idx : indexes)
{
System.out.println(value + " found at " + (idx + 1));
}
}
Bear in mind that what you have implemented is already a binary search. The extra code to find additional matching indexes would not fall under the usual definition of a binary search.

Shifting elements by index and value in Java

I need to write a code that will shift elements to the right for k places, and the element is index position. Also I should suppose that my array List is linked in circle.
Example:
list = [1,2,3,4];
list.shiftRight(1,2);
list = [1,3,4,2]
For the circle list I think of:
list = [1,2,3,4];
list.shiftRight(2, 3);
list = [1,3,2,4].
This is my code but it's not working properly.
public void shiftRight(int index, int k) throws ArrayIndexOutOfBoundsException{
if (index < 0 || index > this.list.size())
throw new ArrayIndexOutOfBoundsException();
if (k + index > this.list.size()) {
int element = this.list.remove(index);
this.list.add(this.list.size() - k, element);
} else {
int element = this.list.remove(index);
this.list.add(k + index , element);
}
//System.out.println("ShiftedRight " + this.list);
}
Also here is the code for shifting elements to the left which also doesn't work. ^_^
public void shiftLeft(int index, int k) throws ArrayIndexOutOfBoundsException {
if (index < 0 || index > this.list.size())
throw new ArrayIndexOutOfBoundsException();
if (k + index > this.list.size()) {
int element = this.list.remove(index);
this.list.add(this.list.size() - k + index, element);
} else {
int element = this.list.remove(index);
this.list.add(index - k, element);
}
//System.out.println("ShiftedLeft " + this.list);
}
You're on the right track. There are a few edge conditions to consider. And you have to be very careful with indexes, lengths and being off by one.
Firstly, note that in a list of 4 elements, the valid indexes are [0..3]. That is, the maximum index is one less than the length.
Secondly, k appears to be unbounded. I assume it's meant to be non-negative. If so, you should check for this. It can be many times larger than the length of the list, ie. you can loop around more than once. So we use modulo arithmetic.
Thirdly, when you remove an element from the list the indexes change. You need to handle this when adding the element back in.
public void shiftRight(int index, int k)
throws ArrayIndexOutOfBoundsException
{
int length = this.list.size();
// Note: index cannot be equal to length. You were testing for >.
if ((index < 0) || (index >= length))
{
throw new ArrayIndexOutOfBoundsException('out of range index: ' + index);
}
int shift = k % length; // Use modulo arithmetic to determine a shift in the range [0..length).
if (shift == 0)
{
return; // No change, we're done.
}
int newIndex = (index + shift) % length; // Calculate where to move to, again using modulo arithmetic, to get the loop around.
int element = this.list.remove(index);
this.list.add(newIndex, element);
}
I've only hand-tested this so let me know if there are any issues. shiftLeft() should be similar, although watch out for negative numbers in modulo arithmetic.

How do I use a recursive algorithm to determine whether the array contains two elements that sum to a given integer?

Okay guys thanks for all the help! Special thanks to #pjs for giving me an idea of how to do it. Here is my new code, but for some reason it won't reach one of the base cases. Sorry if I deleted the old code, this is the first time I posted here and I am not sure if I should answer my own question with the new code.
//initialized int start = 0
//initialized int end = length of the array
//here goes the constructor
public boolean kPairSum(Integer k) {
if (sortedIntegerArray.length < 2) { //if array is less than two return false
return false;
}
else if (start == end) { //once the start and the end meets. This is the base case that doesn't seem to work for me.
return false;
}
else {
int currentStart = sortedIntegerArray[start]; //get first int in the array
int currentEnd = sortedIntegerArray[end-1]; //get the very last int in the array
int sum = currentStart + currentEnd; //get the sum
if (k.equals(sum)) { //compare sum and k if equal
return true;
}
else if (sum <k) { //if sum is less than k then increment value of start
start++;
return kPairSum(k);
}
else if (sum > k) { //if sum is greater than k then it decrements value of end
end--;
return kPairSum(k);
}
else { //not sure if this is right, should I just get rid of the else if statement for sum > k and change it to just an else? I wrote this down cause it has to return a type of boolean.
return kPairSum(k);
}
}
Your array is called sortedIntegerArray, but you don't seem to be leveraging that fact.
Start by summing the two ends of the array. If the sum is smaller than k, one of the two elements of the sum has to be larger. You can only get a larger value by incrementing the lower index because the elements are ordered. Similarly, if the sum is larger than k, one of the two elements has to be smaller, so you need to decrement the upper index. In either case, the structure of the problem is the same but you're now operating on a subset of the array specified by which of the indices you incremented/decremented. Base cases are that you found two values which sum to k, or that the indices have met somewhere. The recursion should leap out at you. Since each recursive call either increments or decrements a boundary index until they meet in the middle, it's O(n).
Your recursive call is never invokes:
if (sum == k) { //compare to given k
return true;
} else if (xx == sortedIntegerArray.length-1 || sum != k) {
return false;
}
Note that you basically have two choices: sum==k, and then - return true, or sum!=k - and then return false. The recursive invokation is not reachable.
An O(n) (average case) solution can be achieved using a hash table. The idea is to add each element to the hash table while iterating, and check if there is an existing element that completes to k.
for each element e in arr:
if e is in table:
return true
table.add(k-e)
return false //no pair was found that sums to k
A recursive solution that checks all pairs, is basically brute force that is similar to a nested for loop.
//i is the index we are now checking, b is a boolean indicating we have already reduced one element
kSum(k,i,b):
if i == arr.length
return false
if b == true && k == 0:
return true
if b == false:
return kSum(k-arr[i],i+1,true) || kSum(k,i+1,false)
else:
return kSum(k,i+1,b)
I have two implementations here:
One I initially got to work and with Amit answer, I improved it further. It also prints/return the indices that make up the sum. works with both sorted and unsorted array in O(n). ofcourse, this is not recursive.
public static void sumArray2(int[] arr, int sum){
Map <Integer, Integer> map = new HashMap<>();
for (int i=0; i < arr.length;i++){
map.put(arr[i], i);
}
for (int i =0; i < arr.length;i++){
int diff = sum-arr[i];
if (map.containsKey(diff) && i!=map.get(diff)) {
System.out.printf("The two indices are %s and %s%n ",i,map.get(diff));
return ;
}
}
System.out.printf("The sum:%s cannot be formed with given array:%s",sum,Arrays.toString(arr));
return ;
}
//returns a boolean if sum could be formed.
public static boolean sumArray3(int[] arr, int sum){
Map <Integer, Integer> map = new HashMap<>();
for (int i =0; i < arr.length;i++){
int diff = sum-arr[i];
if (map.containsKey(arr[i])) {
System.out.printf("The two indices are %s and %s%n ",i,map.get(arr[i]));
return true;
}
map.put(diff,i);
}
System.out.printf("The sum:%s cannot be formed with given array:%s",sum,Arrays.toString(arr));
return false;
}
don't know how to add formatted comment, so here is enhanced version, than Amit provided, works with O(n) :)
def check(source, need):
target = [need-i for i in source]
target.reverse()
i = 0
j = 0
# walk thru lists same "merge" to find a match
for i in xrange(0, len(source)):
while j < len(target) and source[i] > target[j]:
j=j+1
if i != len(source)-j-1 and j < len(target) and source[i] == target[j]:
return True
return False

Recursively check if an array represents a heap

How do we check if an array represents a heap data structure recursively?
Assume it is an array of integers, and I am checking for max heap.
The following is what I came up with, but I don't know if that is correct.
public static boolean isHeap(int[] arr) {
if (arr = null)
return false;
return isHeapTree(arr, 0);
}
private static boolean isHeapTree(int[] arr, int i) {
if (i = arr.length - 1)
return true;
// check if a parent's value is larger or equal to both of
// its left child and right child
else if (arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2])
return (isHeapTree(arr, 2i + 1) && isHeapTree(arr, 2i + 2));
else
return false;
}
is it possible a binary heap could be incomplete? say:
100
/ \
50 20
/ \ \
30 40 26
Some comments:
You definitely don't need the while loop - you always return after the first iteration
2i + 1 doesn't work in java, you need to use 2*i + 1
arr[2*i + 1] and arr[2*i + 1] may throw and ArrayIndexOutOfBoundsException so you need to either manually do a range check, or wrap it in a try.. catch block
Typically, when a heap is stored in an array, it is always packed to the left. In other words, when the heap has n elements, the all elements in the array in the index range [0, n-1] contain elements. Every insert starts by placing the element at index size(), and then it jumps up until it is smaller than its parent.
So the approach you are taking can succeed.
Also note that in your code, you can deal with going out of bounds with a small change to your guard on top:
public static boolean isHeap(int[] arr, int size) {
return (null == arr) ? false : isHeapTree(arr, size, 0);
}
private static boolean isHeapTree(int[] arr, int size, int i) {
assert i >= 0;
assert size <= arr.length;
if (i >= size) return true;
...

Categories

Resources