I have sorted array
{1,2,3,5,5,5,7,8,8}
I would like to count how many times the number that i am sending is found in the array in longn only.
for example:
public static int count(int[] array,5)
will reply 3
public static int count(int[] array,8)
will reply 2
so my plan is:
1) to do a binary search to find the number
2) binary search the top border index and the bottom border index.
3) print (top index - bottom index) will give me the time of target number in the array.
Is my code is logn ?
Please help! :)
public class binarySearch
{
public static void main(String[]args)
{
System.out.println("d");
int[]data={1,1,2,3,1,1,1};
System.out.println(count(data,1));
}
public static int count(int[] a, int x)
{
int low=0;
int high = a.length-1;
int count=0;
while(low <=high)
{
int mid=((low+high)/2);
if(x>a[mid])
low=mid+1;
if(x<a[mid])
high=mid-1;
if(x==a[mid])
{
int top=findTopIndex(a,x,mid);
int bottom=findBottomIndex(a,x,mid);
return (top-bottom);
}
}
return 111111111;
}
public static int findTopIndex(int[] a, int x, int index)
{
int low=index;
int high = a.length-1;
int mid;
if(x==a[high])
return high;
while(low <= high)
{
mid=((low+high)/2);
if(x<a[mid]&&x==a[mid-1])
return mid-1;
else if(x==a[mid])
low=mid+1;
else if(a[mid]>x && a[mid-1]!=x)
high=mid-1;
}
return 11111111;
}
public static int findBottomIndex(int[] a, int x, int index)
{
int low=0;
int high = index-1;
int mid;
if(x==a[low])
return low-1;
while(low <= high)
{
mid=((low+high)/2);
if(x>a[mid]&&x==a[mid+1])
return mid;
else if(x==a[mid])
high=mid-1;
else if(a[mid]<x && a[mid+1]!=x)
low=mid+1;
}
return 111;
}
}
What you have written is really close to the solution you need. You first do a binary search to find a single instance of the number you are searching for(let's say its found on position index) and then you do two more binary searches -one for the sequence 0, index, and one for index, size to find up to where in both sequences is the number found.
So I suggest you simply pass an index to both findTopIndex and findBottomIndex and make use of it. I can write the whole solution but it will be better for you to come to it on your own.
Related
So the question is
You are given a 0-indexed integer array nums and an integer k.
You are initially standing at index 0. In one move, you can jump at most k steps forward without going outside the boundaries of the array. That is, you can jump from index i to any index in the range [i + 1, min(n - 1, i + k)] inclusive.
You want to reach the last index of the array (index n - 1). Your score is the sum of all nums[j] for each index j you visited in the array.
Return the maximum score you can get.
Example 1:
Input: nums = [1,-1,-2,4,-7,3], k = 2
Output: 7
Explanation: You can choose your jumps forming the subsequence [1,-1,4,3] (underlined above). The sum is 7.
I wrote a recursive solution in which we explore all the possibilies . If the function is called at index ind , then the value at index ind is added to a variable curSum for the next function call.
The base condition is when we reach the last index , we will return curSum+value of last index.
Here is the code:
class Solution {
static int min= Integer.MIN_VALUE;
public int maxResult(int[] nums, int k) {
return max(nums,0,k,0);
}
public int max(int [] nums, int ind, int k, int curSum)
{
if(ind==nums.length-1)
return curSum+nums[ind];
int max=Integer.MIN_VALUE;
for(int i=ind+1;i<=Math.min(nums.length-1,ind+k);i++)
max=Math.max(max, max(nums,i,k,curSum+nums[ind]));
return max;
}
}
Code works fine except the exponential complexity ofcourse.
I tried memoizing it as
class Solution {
static int[] dp;
static int min= Integer.MIN_VALUE;
public int maxResult(int[] nums, int k) {
dp=new int[nums.length];
Arrays.fill(dp,min);
return max(nums,0,k,0);
}
public int max(int [] nums, int ind, int k, int curSum)
{
if(ind==nums.length-1)
return curSum+nums[ind];
if(dp[ind]!=min)
return dp[ind];
int max=Integer.MIN_VALUE;
for(int i=ind+1;i<=Math.min(nums.length-1,ind+k);i++)
max=Math.max(max, max(nums,i,k,curSum+nums[ind]));
return dp[ind]=max;
}
}
But this solution gives the wrong max everytime and I am not quite able to figure out why.
Any hints will be appreciated.
Thanks
You only need to memoize dp[index] instead of calling f(index, currSum).
Take for example present arr.length = 5, k = 2
For index-2 you need wether index 3 or 4 gives better points to you irrespective of your present point.
Better way would be :
class Solution {
static int[] dp;
static int min= Integer.MIN_VALUE;
public int maxResult(int[] nums, int k) {
dp=new int[nums.length];
Arrays.fill(dp,min);
return max(nums,0,k,0);
}
public int max(int [] nums, int ind, int k, int curSum)
{
// base-case
if(ind==nums.length-1)
return curSum+nums[ind];
// if already memoized
if(dp[ind]!=min)
return dp[ind] + curSum;
// if not memoized, calculate value now
int max=Integer.MIN_VALUE;
for(int i=ind+1;i<=Math.min(nums.length-1,ind+k);i++)
max=Math.max(max, max(nums,i,k,nums[ind]);
// memoize here
dp[ind] = max
return dp[ind] + curSum;
}
}
Is it possible to count the number of comparisons made by a recursive binary search? If so, how?
Here is the search I am referring to:
//binary search
public static int binarySearch(int[] items, int start, int end, int goal)
{
if (start > end)
return (-1);
else
{
int mid = (start + end)/2;
if (goal == items[mid])
return (mid);
else
if (goal < items[mid])
return (binarySearch(items, start, mid - 1, goal));
else
return (binarySearch(items, mid + 1, end, goal));
}
}//end binarySearch
Declare your count variable outside of the method. Then add 1 each time that you call the method.
long count = 0;
//binary search
public static int binarySearch(int[] items, int start, int end, int goal)
{
count += 1
if (start > end)
return (-1);
else
{
int mid = (start + end)/2;
if (goal == items[mid])
return (mid);
else
if (goal < items[mid])
return (binarySearch(items, start, mid - 1, goal));
else
return (binarySearch(items, mid + 1, end, goal));
}
}//end binarySearch
Your most likely approach if you want to caller to be able to access the count is to pass in an accumulator into your binary search. In java 7 or less, AtomicLong may be a good choice (though it does have some overhead). In java 8, a LongAdder would also be good:
public static int binarySearch(int[] items, int start, int end, int goal, AtomicLong counter) {
}
and each time you do a comparison, you would just increment the count:
counter.incrementAndGet()
When you exit the search, the counter will contain the number of comparisons:
long count = counter.get()
I would like to generate an index from 0 to size - 1, uniformly, but different than any index in the given set excluded.
size is around 100. There are typically 1, 2 or 3 exluded indices. Indices in excluded are unique and not sorted.
Ideally, the header will be with multiple arguments, maybe something like this:
int getRandomIndex(Random rand, int size, int... i)
Or, if this ... multi arguments are slow (are they?) we can pass simple int[] excluded array or something.
How to do it fast? getRandomIndex() is called millions of times.
static int getRandomIndex(Random rand, int size, Integer... excludes) {
List<Integer> excludeList = Arrays.asList(excludes);
int number;
do {
number = rand.nextInt(size);
} while (excludeList.contains(number));
return number;
}
You can allocate array of possible values 0..size-1, remove all known indexes and select random element from the rest.
If indexes array is sorted and all values are unique, you can do it without intermediate array of values :
int getRandomIndex(Random rand, int size, int... ii)
{
int result = rand.nextInt(size - ii.length);
for(int i : ii) {
if(result >= i) {
++result;
}
}
return result;
}
Edit: I found mistake in if condition, corrected.
EDIT:
int getRandomIndex(Random rand, int size, int i) {
int result = rand.nextInt(size - 1);
if(result >= i) {
result++;
}
}
int getRandomIndex(Random rand, int size, int i, int j) {
int result = rand.nextInt(size - 2);
if(i > j) {
int tmp = j;
j = i;
i = tmp;
}
if(result >= i) {
result++;
}
if(result >= j) {
result++;
}
return result;
}
And similar function for (i,j,k).
A function that call rand.next only one time might be faster of any function, that asks for random number several times.
I'd do it a bit differently. To pick a random number less than size but which isn't i or j, you can pick a random number between 0 and size-3 inclusive. If that number is i then return size-2 and if the number is j then return size-1. Otherwise return the original random number.
There is the edge case of i or j being within 2 of size, but I leave that to the interested reader. Actually I think it just works out OK.
This can be generalized to pick a number less than size that isn't in an array of integers. Choose a number less than size - the array length - 1.
You could use a Set fro fast look up
int getRandomIndex(Random rand, int size, Integer... i) {
return getRandomIndex(rand, size, new HashSet<Integer>(Arrays.asList(i)));
}
int getRandomIndex(Random rand, int size, Set<Integer> x) {
int result;
do {
result = (int) (rand.nextDouble() * size);
} while (x.contains(result));
return result;
}
If the set of all indices is predefined then you could have the Set x final static and spare building it every time you call the method.
EIDT
Well If performance is an issue then I would say that your first approach with while(r == i || r == j || r == k) is neither bad nor ugly, just have three overloads of your method and call the appropriate one you need, the call will look exactly the same as with a val-len-array.
You can't have an evaluation faster than (r == i || r == j || r == k)
int getRandomIndex(Random rand, int size, int i)
int getRandomIndex(Random rand, int size, int i, int j)
int getRandomIndex(Random rand, int size, int i, int j, int k)
Assuming many consecutive calls uses the same size and excluded values...
First, initializing an array of all the allowable indices
When getRandomIndex is called, simply pick a random element of this array
Code:
int[] indices;
void init(int size, Integer... excluded)
{
indices = new int[size-excluded.length];
int pos = 0;
Set<Integer> excludedSet = new HashSet<Integer>(Arrays.asList(excluded));
for (int i = 0; i < size; i++)
{
if (!excludedSet.contains(i))
{
indices[pos++] = i;
}
}
}
int getRandomIndex(Random random)
{
return indices[random.nextInt(data.length)];
}
Example usage:
init(100, 50, 23, 10);
Random random = new Random();
for (int i = 0; i < 200; i++)
{
System.out.println(getRandomIndex(random));
}
So I am working on a project for my class and I am currently stuck on creating a QuickSort class to sort an Array of 1000 names. I have a template I am using from a previous Lab we did in class which we are supposed to base it off of; but in the lab we used an array of Integers and I am struggling with how to convert it so it will work with Strings; names. Thanks for your help or any suggestions, the code is below.
Updated post; So I made my comparison in my Name class
public int compareTo(Object other) {
int result;
if (name.equals(((Name) other).name))
result = name.compareTo(((Name) other).name);
else
result = name.compareTo(((Name) other).name);
return result;
}
And I've tried to re-work my QuickSort..I'm struggling with the swap method.
private ArrayList<Name> data;
public QuickSort(ArrayList<Name> initialValue){
data=initialValue;
}
public void sort(ArrayList<Name> namelist, int i, int j){
sort(0, data.size()-1);
}
public void sort(int from, int to){
if (from >= to)
return;
int p = partition(from, to);
sort(from, p);
sort( p + 1, to);
}
private int partition(int from, int to){
Name pivot = data.get(from);
int i = from - 1;
int j = to + 1;
while(i<j){
i++; while(data.get(i).compareTo(pivot) < 0) i++;
j--; while(data.get(j).compareTo(pivot) < 0) j--;
if(i<j) swap(i,j);
}
return j;
}
private void swap (int i, int j){
Name temp = data.get(i);
data.equals(i) = data.get(j);
data = temp;
}
particularly the "data.equals(i) = data.get(j) line and the data = temp; I am sure i'm doing something stupid and easy.
update;
private void swap (int i, int j){
Name temp = data.get(i);
data.get(j).equals(data.get(i));
data.get(j).equals(temp);
}
possibly?
Posting the code that will solve the problem would be easy but won't help you to learn the meaning of QuickSort (or another sorting algorithm).
The heart of the QuickSort is exchanging the elements here:
while(i<j){
i++; while(data[i] < pivot) i++;
j--; while(data[j] > pivot) j--;
if(i<j) swap(i,j);
}
As you can see, you're comparing the elements of the data array against the pivot variable. Since they're ints, you can easily compare them using <. Now, you have to do something similar but for Strings. Thankfully, Strings can be compared using String#compareTo method. I'll let you this implementation for String (otherwise I will present the homework assignment as mine =P).
For a more generic solution to the problem, you have two options:
Making your class implement the Comparable interface, so you will have a compareTo method. A basic
sample implementation:
public class Name implements Comparable<Name> {
#Override
public int compareTo(Name name) {
return ... //comparison logic...
}
}
Using it in your QuickSort
pivot.compareTo(...);
Using an instance of Comparator interface. You will use Comparator#compare for this. A basic sample implementation:
public class NameComparator implements Comparator<Name> {
#Override
public int compare(Name name1, Name name2) {
return ... //comparison logic...
}
}
Using it in your QuickSort
NameComparator nameComparator = new NameComparator();
nameComparator.compare(..., ...);
You can use a comparator: Comparator.compare(o1, o2) returns -1, 0 or 1 if the objects are less, equal or greater.
Strings in java are actually comparable, some sort of a companion interface:
int compareTo(T other);
API Do: http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html
Note that in string comparison is by equals method:
data.get(j) == pivot => data.get(j).equals(pivot)
You will have to set a String value to compare it to something. So by setting the pivot value to compare it to itself it will return zero. Since it is unlikely that all Strings will equal your pivot value then anything compared to pivot value will be returned as -1 OR 1. By doing this your if statement will determine which way the swap value is sent( Higher OR Lower) then your pivot value.
ObjectQuickSorter sortStrings = new ObjectQuickSorter();
sortStrings.sort(arrayHere);
class ObjectQuickSorter{
void sort(String[] array){
doQuickSort(array, 0, array.length -1);
}
private static void doQuickSort(String[] array,int start, int end){
int pivotPoint;
if(start < end){
pivotPoint = partition(array, start, end);
doQuickSort(array, start, pivotPoint -1);
doQuickSort(array, pivotPoint + 1, end);
}
}
private static int partition(String[] array, int start, int end){
String pivotValue;
int endOfLeftList;
int mid = (start + end)/2;
swap(array, start, mid);
pivotValue = array[start];
endOfLeftList = start;
for(int scan = start + 1; scan <= end; scan++){
// trying to compare pivot = string value to array[scan] position value
// doing this by setting pivot value compare to itself to return 0
// then also comparing pivot value to array[scan] to return -1, 0, 1
// if return is 0 or 1 then it ignores it
if( array[scan].compareTo(pivotValue) < array[start].compareTo(pivotValue)){
endOfLeftList++;
swap(array, endOfLeftList,scan);
}
}
swap(array, start, endOfLeftList);
return endOfLeftList;
}
private static void swap(String[] array, int a, int b){
String temp;
temp = array[a];
array[a] = array[b];
array[b] = temp;
}
}
I am trying to write a program that will take an ArrayList of sorted integers, and there will be a binary search method where you specify the range and the values that you want to be returned from the ArrayList.
import java.util.ArrayList;
public class ArraySearch {
ArrayList<Integer> myArrayList = new ArrayList<Integer>();
static ArrayList<Integer> range = new ArrayList<Integer>();
public static ArrayList<Integer> binarySearch(ArrayList<Integer> arrayList, int min, int max, int first, int last)
throws NotFoundException {
if(first > last) {
throw new NotFoundException("Elements not found.");
}
else {
int middle = (first + last) /2;
int mid_number = arrayList.get(middle);
if(mid_number >= min && mid_number <= max)
{
range.add(middle);
}
if(mid_number <= min) {
if(mid_number == min) {
range.add(arrayList.get(middle));
return binarySearch(arrayList, min, max, first, middle-1);
}
return binarySearch(arrayList, min, max, first, middle-1);
}
else {
if(mid_number == max) {
range.add(arrayList.get(middle));
return binarySearch(arrayList, min, max, middle+1,last);
}
return binarySearch(arrayList, min, max, middle+1,last);
}
}
}
public static void main (String [] args) throws NotFoundException {
ArrayList<Integer> a = new ArrayList<Integer>();
a.add(0);
a.add(1);
a.add(2);
a.add(3);
a.add(6);
a.add(7);
a.add(7);
a.add(10);
a.add(10);
a.add(10);
binarySearch(a, 3, 7, 0, 9);
}
}
Could I please get some help?
I have no idea what the base case condition should be that should return the ArrayList range. And I think I might have got the logic in the binary search method wrong.
First , find the lower index range of the element. then , find the upper index range of the element .
To find lower index range, when you find the element, instead of breaking out of the loop, like we do so in normal search. put the value in index and make the mid one less than the current index you are checking. This will make the loop go again to find the lower index and not stop at the first index.
Similarly for the upper index , update start to the current index we are checking + 1.
Have a look at the code.
public ArrayList<Integer> searchRange(ArrayList<Integer> a, int b) {
int first=lowerIndex(a,b);
int last=upperIndex(a,b);
ArrayList<Integer> result= new ArrayList<Integer>();
result.add(first);
result.add(last);
return result;
}
public int upperIndex(ArrayList<Integer> a, int b) {
int index=-1; //will return -1 if element not found.
int start=0;
int end=a.size()-1;
while(start<=end){
int mid=(start+end)/2;
if(a.get(mid)==b){
index=mid; //Update Index, which is the upper index here.
start=mid+1; // This is the main step.
}
else if(a.get(mid)>b){
end=mid-1;
}
else{
start=mid+1;
}
}
return index;
}
public int lowerIndex(ArrayList<Integer> a, int b) {
int index=-1; // will return -1 if element not found
int start=0;
int end=a.size()-1;
while(start<=end){
int mid=(start+end)/2;
if(a.get(mid)==b){
index=mid; //Update Index, which is the lower index here.
end=mid-1; // This is the main step .
}
else if(a.get(mid)>b){
end=mid-1;
}
else{
start=mid+1;
}
}
return index;
}