Java Ternary Search - java

I am trying to perfrom a ternary search on a array of strings. I have got most of code down and I think I am going on the right track but can't seem to get any results other then -1. Below is the code that I have genearated thus far. I know the problem is in the search algorithm. I do not want to use any built is as I am learning.
public static void main(String[] args) {
//declare a string array with initial size
String[] songs = {"Ace", "Space", "Diamond"};
System.out.println("\nTest binary (String):");
System.out.println(search(songs,"Ace"));
}
public static int search(String[] x, String target) {
int start=0, end=x.length;
while (start > end) {
int midpoint1 = start+(end - start)/3;
int midpoint2 = start +2*(end-start)/3;
if ( target.compareTo(x[midpoint1]) == 0 )
return midpoint1;
else if ( target.compareTo(x[midpoint2]) == 0 )
return midpoint2;
else if ( target.compareTo(x[midpoint1]) < 0 )
return end = midpoint1-1;
else if ( target.compareTo(x[midpoint2]) > 0 )
return start = midpoint2+1;
}
return -1;
}

You never get into the loop.
int start=0, end=x.length;
while (start > end)

You're while statement is wrong, it should contain start < end. I recomend learning the debug settings that are on most IDEs because if you're going to stick around it makes it so much easier to view the states of vars.

Try this corrected version, additionally to the bug identified by the Thomas and user2789574, you also have a bug in the recursion:
public static void main(String[] args) {
//declare a string array with initial size
String[] songs = {"Ace", "Space", "Diamond"};
System.out.println("\nTest binary (String):");
System.out.println(search(songs, "Ace", 0, 3));
}
public static int search(String[] x, String target, int start, int end) {
if (start < end) {
int midpoint1 = start + (end - start) / 3;
int midpoint2 = start + 2 * (end - start) / 3;
if (target.compareTo(x[midpoint1]) == 0) {
return midpoint1;
} else if (target.compareTo(x[midpoint2]) == 0) {
return midpoint2;
} else if (x[midpoint1].compareTo(x[midpoint2]) < 0) {
return search(x, target, midpoint1, end);
} else {
return search(x, target, start, midpoint2);
}
}
return -1;
}

end = x.length,will always return numeric value greater than zero for not null string and it's comparison with start =0 , it will never enter into the loop.

I am not sure if its still relevant now, but here is the ternary search done with loops in java(assuming that the array is pre-sorted):
public static int ternSearch(String[] x, String target) {
if((target.toLowerCase()).compareTo(x[0].toLowerCase()) == 0)
{
return 0;
}
if((target.toLowerCase()).compareTo(x[x.length - 1].toLowerCase()) == 0)
{
return x.length-1;
}
int mid1 = (int) Math.ceil( x.length/3);
if((target.toLowerCase()).compareTo(x[mid1].toLowerCase()) == 0)
{
return mid1;
}
int mid2 = (int) Math.ceil( x.length*2/3);
if((target.toLowerCase()).compareTo(x[mid2].toLowerCase()) == 0)
{
return mid2;
}
if((target.toLowerCase()).compareTo(x[0].toLowerCase()) > 0&& (target.toLowerCase()).compareTo(x[mid1].toLowerCase()) < 0)
{
for (int i = 1; i < mid1; i++)
{
if((target.toLowerCase()).compareTo(x[i].toLowerCase()) == 0)
{
return i;
}
}
}
else if((target.toLowerCase()).compareTo(x[mid1].toLowerCase()) > 0&& (target.toLowerCase()).compareTo(x[mid2].toLowerCase()) < 0)
{
for (int i = mid1+1; i < mid2; i++)
{
if((target.toLowerCase()).compareTo(x[i].toLowerCase()) == 0)
{
return i;
}
}
}
else if((target.toLowerCase()).compareTo(x[mid2].toLowerCase()) > 0&& (target.toLowerCase()).compareTo(x[x.length-1].toLowerCase()) < 0)
{
for (int i = mid2+1; i < x.length-2; i++)
{
if((target.toLowerCase()).compareTo(x[i].toLowerCase()) == 0)
{
return i;
}
}
}
return -1;
}

Related

For loop isn't returning -1 when I want it to as per the conditions

The issue is that when an integer lesser than or equals to 0 is passed as a parameter for 'end', and when 'end' is lesser than 'start' it doesn't return -1.
public static boolean isOdd (int number)
{
if (number < 0)
{
return false;
}
else
{
if (number % 2 != 0 )
{
return true;
}
else
{
return false;
}
}
}
This is method to test the parameter 'start' and 'end'
public static int sumOdd (int start, int end)
{
int sum = 0;
for (int i = start; i<=end; i++)
{
if ((start<=0) || (end<=0) || (end<start))
{
return -1;
}
else
{
if (isOdd(i))
{
sum+=i;
}
}
}
return sum;
}
The problem lies in your for loop.
You instructed the loop to run when i was smaller or equal to end. That's sounds good on paper, but you do realize that this statement
if ((start<=0) || (end<=0) || (end<start))
will never be run (in the case that end is larger than start), since i is start, and if end is bigger than start, it is therefore bigger than i, which wouldn't satisfy your previous defined condition in the for loop, i is smaller or equal to end. Therefore, the for loop will never run.
You should be doing:
public static int sumOdd(int start, int end) {
int sum = 0;
if ((start <= 0) || (end <= 0) || (end < start)) {
return -1;
} else {
for (int i = start; i <= end; i++) {
if (isOdd(i)) {
sum += i;
}
}
return sum;
}
}
Test Run
sumOdd(1, 0) returns -1
sumOdd(1, 3) returns 4

How can I show the value of array with the Binary Search Tree of Comparison?

I going to do searching the value in the array, did I need to create a method to handle it? For example, the array logged 32,21,13,44,22, and I going to find 22 of the comparison. How can I implement this?
public class binarySearch {
public static void main(String [] args) {
int i = binarySearch(0, new int[]{32,21,13,44,22});
System.out.println("Iterations: " + i);
}
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right) / 2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
} else if (comp > 0) {
left = mid + 1;
} else {
break; // success
}
}
return i;
}
}
My final answer is here. May help you all in the future.
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right) / 2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
} else if (comp > 0) {
left = mid + 1;
} else {
break; // success
}
}
return i;
}
If you have shuffled array, all you can do is go through an array and find your number.
BinarySearch works only with sorted array. I think your solution could look like this:
public static int binarySearch(int[] arr, int key) {
Arrays.sort(arr);
return Arrays.binarySearch(arr, key);
}

Each substring of a certian length of a binary substring should have at least one '1' character

You have been given a binary string containing only the characters '1' and '0'.
Calculate how many characters of the string need to be changed in order to make the binary string such that each of its substrings of at least a certain length contains at least one "1" character.
I came to think of the following idea but it fails for many testcases:
public static int minimumMoves(String s, int d) {
int n = s.length();
int i=0, answer = 0;
while(i<n)
{
boolean hasOne = false;
int j=i;
while(j<n && j<i+d)
{
if(s.charAt(j) == '1')
{
hasOne = true;
break;
}
j++;
}
if(!hasOne) {
answer++;
i += d;
}
else i++;
}
return answer;
}
Also my algorithm runs on O(|s|2) time. Can anyone suggest ideas on O(|s|) time?
Just throwing off an idea:
return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()
You just need to break ensure there is no run of d zeros.
public static int minimumMoves(String s, int d) {
int result = 0;
int runLength = 0;
for(char c: s.toCharArray()) {
if (c == '0') {
runLength += 1;
if (runLength == d) { // we need to break this run
result += 1;
runLength = 0;
}
} else {
runLength = 0;
}
}
return result;
}
I used the sliding window technique and Deque to solve this. This is my accepted solution:
public static int minimumMoves(String s, int d) {
int n = s.length();
Deque<Character> dq = new LinkedList<>();
int count = 0, answer = 0;
for(int i=0; i<d; i++)
{
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
}
if(count == 0) {
answer++;
count++;
dq.removeLast();
dq.addLast('1');
}
int i=d;
while(i<n)
{
if(dq.getFirst() == '1') count--;
dq.removeFirst();
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
if(count == 0)
{
answer++;
dq.removeLast();
dq.addLast('1');
count++;
}
i++;
}
return answer;
}
You just need to use a sliding window and a count of 1s so far at each index. Use a sliding window of d and if you don't see any ones so far, update the last index of that window with 1 and increment the result.
Code below:
public static int minimumMoves(String s, int d) {
int n = s.length();
int[] count = new int[n+1];
int res = 0;
for ( int i = 1; i <= d; i++ ) {
if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
else count[i] = count[i-1];
}
if ( count[d] == 0 ) {
res++;
count[d] = 1;
}
for ( int i = d+1; i <= n; i++ ) {
if ( s.charAt(i-1) == '0' ) {
count[i] = count[i-1];
int ones = count[i] - count[i-d];
if ( ones == 0 ) {
count[i] = count[i-1] + 1;
res++;
}
} else {
count[i] = count[i-1] + 1;
}
}
return res;
}
Thought of another implementation you can do for this by working from the maximum possible changes (assumes at start that all values are '0' in String), reduce it when it finds a '1' value, and then jump to the next substring start. This allows it to run in O(n) and Ω(n/m) (n = String length, m = Substring length).
public static int minimumMoves(String s, int d)
{
char[] a = s.toCharArray();
//Total possible changes (not counting tail)
if(a.length < d)
return 0;
int t = (int) a.length / d;
//Total possible changes (counting tail)
//int t = (int) Math.ceil((double) a.length / (double) d);
for(int i = 0; i < a.length; i++)
{
if(a[i] == '1')
{
t--;
//Calculate index for start of next substring
i = (i / d + 1) * d - 1;
}
}
return t;
}

Efficiently, get the count of numbers in a sorted array that is less than a given number using binary search

My problem statement is this -
Find the count of numbers in a sorted array that are less than a given number, and this should be done efficiently with respect to time. I wrote a program using binary search that gets the count but time complexity wise it's failing. Need help in achieving this.
import java.util.Arrays;
public class SortedSearch {
public static int countNumbers(int[] sortedArray, int lessThan) {
if(sortedArray.length ==1 || sortedArray.length == 0) {
return singleElement(sortedArray, lessThan);
}
else {
return binarySearch(sortedArray, lessThan);
}
}
public static int singleElement(int[] sortedArray, int searchVal) {
if(sortedArray.length == 0) {
return 0;
}
if(sortedArray[0] < searchVal) {
return 1;
}
return 0;
}
private static int binarySearch(int[] sortedArray, int searchVal) {
int low = 0;
int high = (sortedArray.length)-1;
int mid = (low + high)/2;
if((sortedArray.length == 0) || (sortedArray[0] > searchVal)) {
return 0;
}
if(sortedArray[high] < searchVal) {
return sortedArray.length;
}
if(sortedArray[high] == searchVal) {
return sortedArray.length-1;
}
if(sortedArray[mid] < searchVal) {
int newLow = low;
int newHigh = calculateNewHigh(sortedArray, newLow, 0, searchVal);
int[] newArray = Arrays.copyOfRange(sortedArray, newLow, newHigh+1);
return newArray.length;
}
else {
int newLow = low;
int newHigh = mid;
int[] newArray = Arrays.copyOfRange(sortedArray, newLow, newHigh+1);
return binarySearch(newArray, searchVal);
}
}
private static int calculateNewHigh(int[] sortedArray, int low, int previousHigh, int searchVal) {
int newHigh = previousHigh + (sortedArray.length-low)/2;
if(sortedArray[newHigh] < searchVal) {
newHigh = calculateNewHigh(sortedArray, newHigh, newHigh, searchVal);
}
if(sortedArray[newHigh] == searchVal) {
newHigh--;
}
if(sortedArray[newHigh] > searchVal) {
newHigh--;
}
return newHigh;
}
public static void main(String[] args) {
System.out.println(SortedSearch.countNumbers(new int[] { 1, 3, 5, 7 }, 4));
}
}
Since you're using Arrays anyway, way not use the Arrays.binarySearch(int[] a, int key) method, instead of attempting to write your own?
public static int countNumbers(int[] sortedArray, int lessThan) {
int idx = Arrays.binarySearch(sortedArray, lessThan);
if (idx < 0)
return -idx - 1; // insertion point
while (idx > 0 && sortedArray[idx - 1] == lessThan)
idx--;
return idx; // index of first element with given value
}
The while loop1 is necessary because the javadoc says:
If the array contains multiple elements with the specified value, there is no guarantee which one will be found.
1) This loop is not optimal if e.g. all values are the same, see e.g. Finding multiple entries with binary search

Recursive Knapsack

I'm trying to implement recursive Knapsack I used the common algorithm to write it as following:
int pack(int n, int s) {
if (n < 0)
return 0;
if (List[n].s > s)
return pack(n-1, s);
else {
int max = Math.max(pack(n-1,s), pack(n-1, s -List[n].s) + List[n].v);
return max;
}
}
Is there anyway I can know which items were packed?
Update: I want only the items that belong to best choice and I don't want to change the function header.
EDIT Using array to track items, what's wrong with this?
int pack(int n , int s)
{
if(n < 0)
{
counter =0;
return 0;
}
if (itemsList[n].s > s)
{
return pack(n-1, s);
}
else
{
int max1 = pack(n-1,s);
int max2 = pack(n-1, s - itemsList[n].s) + itemsList[n].v ;
if(max2 > max1)
{
flag1[counter] = new item();
flag1[counter] = itemsList[n];
counter ++;
}
return max(max1, max2);
}
}
Something like this ?
int pack(int n, int s) {
if (n < 0)
return 0;
if (List[n].s > s)
return pack(n-1, s);
else {
int without = pack(n-1,s);
int with = pack(n-1, s-List[n].s) + List[n].v;
if (with >= without) {
System.out.println(n);
}
return Math.max(with, without);
}
}
or, you can return the list of results:
int pack(int n, int s) {
return reallyPack(n, s, new ArrayList<Item>());
}
int reallyPack(int n, int s, List<Item> l) {
if (n < 0)
return 0;
if (List[n].s > s)
return reallyPack(n-1, s);
else {
int without = reallyPack(n-1,s);
int with = reallyPack(n-1, s-List[n].s) + List[n].v;
if (with >= without) {
l.add(itemsList[n]);
}
return Math.max(with, without);
}
}
and of course, you still know how many items were selected: this is simply the size of the returned list.
You can keep track of all items that are currently selected (using e.g. boolean[] field). Then you have to remember the max in the calls of pack with n < 0.
int maximum;
int currentMax;
boolean[] packed;
boolean[] maxPacked;
int pack(int n, int s) {
if (n < 0) {
if (maximum < currentMax) {
// found better selection
maximum = currentMax;
// copy array
for (int i = 0; i < packed.length; i++)
maxPacked[i] = packed[i];
}
return 0;
}
packed[n] = false;
int maxWithout = pack(n-1, s);
if (List[n].s > s) {
return maxWithout;
} else {
packed[n] = true;
currentMax += List[n].v;
int maxWith = pack(n-1, s -List[n].s) + List[n].v;
currentMax -= List[n].v;
return Math.max(maxWith, maxWithout);
}
}
void callingFunction() {
int maxCost = //...;
// always possible to choose no items
maximum = 0;
currentMax = 0;
packed = new boolean[List.length];
maxPacked = new boolean[List.length];
pack(List.length-1, maxCost);
// print best selection
System.out.println(Arrays.toString(maxPacked));
}

Categories