Inserting into an ArrayList<Occurrence> using Binary Search - java

So this method is passed an arraylist of Occurences, which each contain a string and a frequency. The frequency is the only important part here. But what I need to do is use binary search to insert the last element in the arraylist into the sorted position. Every time I run this code, the insertion position is printed as -1. Am I missing something in my code?
I need to keep track of the indexes in the array I hit during binary search, which shouldn't be too difficult, but explains the return type.
public ArrayList<Integer> insertLastOccurrence(ArrayList<Occurrence> occs) {
ArrayList<Integer> path = new ArrayList<Integer>();
int targetFreq = occs.get(occs.size()-1).frequency; //gets the frequency of the thing we want to insert
//if the array is just 1 value, don't do anything
if(occs.size() == 1){
return null;
}
int start = 0; // The start of the search region
int end = occs.size()-2;// The end of the search region is 1 less than the last position
int position = -1; // Position of the target
// While there is still something list left to search and
// the element has not been found
while (start <= end && position == -1) {
int mid = start + (end - start) / 2; //int mid = (start + end) / 2; // Location of the middle
// Determine whether the target is smaller than, greater than,
// or equal to the middle element
if (targetFreq < occs.get(mid).frequency) {
// Target is smaller; continue the left half
end = mid - 1;
}
else if (targetFreq > occs.get(mid).frequency) {
// Target is larger, continue the right half
start = mid + 1;
}
else {
// Found it!
position = mid;
}
}
System.out.println(position);
return path;
}

So, do I understand this right? You have an ArrayList that is sorted with the exception of the last element (at size()-1) and you want to find the index this element has to be inserted after to regain the sorted property?
I suppose, with the presented code, such an index is only found if the ArrayList contains another element that equals the last (to be inserted) one because position is only set to mid if targetFreq equals the frequency of one of considered elements. Since the last element is never considered (end = size()-2) it is very likely that no equal element is found.

Related

How to get index in Java array that defines start and end of available space

So I tried searching for how to solve this issue I'm having. I need some sort of way in Java to go through an array and find slots (indexes) where it's empty (zeros) so for example I have this array:
int[] arr = {1,1,0,0,0,0,0,1,0,0};
So I want to for example get out two values from here. If my objSize (see below) is 4. I want to get the array index of 2 and 6 since the size of objSize will fit there. These indexes specify space between that is available. I can't really seem to figure this out.
for (int x = 0; x < matrix.length; x++) {
if (arr[x] == 0) {
start = col;
if (start == objSize) {
stop = col;
}
} else {
start = 0;
}
}
How can I do this? I've made an attempt that doesn't work for obvious reasons.
Well, first off I don't really understand your intentions behind the code you already submitted, so it is hard to just improve on it. Instead, I am going to walk you through a similar solution, which is the following.
int objsize = 4;
int[] arr = {1,1,0,0,0,0,0,1,0,0};
int start = 0;
int stop = 0;
for(int i = 0; i < arr.length - 1; i++) {
if(arr[i] != 0){
start = i;
stop = i;
continue;
} else {
stop++;
if(stop-start >= objsize) {
break;
}
}
}
When looking for a sequence in an array, that matches a given condition (in your case 4 consecutive 0 values) you should have two "pointers" for your start and stop value, where the stop value could be the i/the current array pointer as well.
Then you go sequentially through your array and have two general cases:
The value at your current index doesn't match your condition of being 0, so you reset your start and stop pointer to the current position in the array and continue.
Your current index matches the condition. In this case, you leave the starting pointer where it last didn't match the condition and move your stop-pointer forward. If then your finishing criteria of 4 consecutive 0 values is matched, you can leave the for loop over the array.
In the code provided above, the returned/final start and stop value are:
start: exclusively indexed
stop: inclusively indexed.
You said you expected the values returned to be 2 and 6, as this would be the longest concurrent series of 0 values. But as the criteria of 4 consecutive values is already matched at 2 and 5, the code above delivers those values, but can easily be adopted to return the full consecutive sequence.
to go through an array and find slots (indexes) where it's empty (zeros)
In order to find all the slots in the given array, you need a container to store them. A plain array isn't applicable here, because you have to provide the length and it's not possible to know how many slots there are in the given array. For that purpose, we can use ArrayList which utilizes array under the hood and grows gradually while elements are being added into it.
And because each slot is comprised of two values we need an object that encapsulates them. There are two options here: it could be easier a class or record (available since Java 16). And it will look like that:
public record Slot(int start, int end) {
public int getSize() {
return end - start;
}
}
The class below is absolutely identical in terms of functionality. Constructor, getters, equals(), hashCode(), toString() are provided to a record implicitly, but if your choice is class then you have to declare them yourself). Meanwhile with record you need to declare only a custom method getSize().
public class Slot {
private final int start;
private final int end;
public Slot(int start, int end) {
this.start = start;
this.end = end;
}
public int getSize() {
return end - start;
}
// getters, equals(), hashCode(), toString()
}
To implement this algorithm only one local variable start is needed. It's convenient to initialize it will -1 because this illegal position in the array. Therefore it's easy to distinguish the default value of start and beginning of a slot.
The end of the slot will be the first occurrence of the 1 when start != -1. When the end is found a new instance of the Slot is being created and added to the list.
The case when the given array contains a slot at the end must be treated separately after the loop.
A ternary operator start == -1 ? x : start; that is used to update the value of start is an equivalent of if (start == -1) start = x;.
public static void main(String[] args) {
int[] arr = {1,1,0,0,0,0,0,1,0,0};
List<Slot> slots = new ArrayList<>();
int start = -1;
for (int x = 0; x < arr.length; x++) {
if (arr[x] == 0) {
start = start == -1 ? x : start;
} else if(start != -1) {
slots.add(new Slot(start, x));
start = -1;
}
}
// adding the last slot at the end of array
if(start != -1) {
slots.add(new Slot(start, arr.length));
}
System.out.println("All slots: " + slots); // all slots that are found
System.out.println("Slots of size 2: " + getSlotOfSize(slots, 2));
System.out.println("Slots of size 5: " + getSlotOfSize(slots, 5));
}
This method is used to filter out slots of a particular size:
public static List<Slot> getSlotOfSize(List<Slot> slots, int size) {
List<Slot> result = new ArrayList<>(); // a new list to preserve the slots list intact
for (Slot slot: slots) {
if (slot.getSize() == size)
result.add(slot);
}
return result;
}
Output (starting index inclusive, ending index exclusive)
All slots: [Slot[start=2, end=7], Slot[start=8, end=10]]
Slots of size 2: [Slot[start=8, end=10]]
Slots of size 5: [Slot[start=2, end=7]]

Dynamic Programming Problem: Minimizing A Path Through Array

I'm working on a problem right now where we are provided with a 1D array of values, and must find the path from the first index to the last index that sums to the smallest sum. The only restrictions are that if you go forward, the distance you go must be 1 more than the last "jump", while if you go backwards, you must go the same distance as the last "jump". For instance, given an array int[] values = new int[]{4, 10, 30, 1, 6}, you need to find the path that gets you from position 0 (4) to position 4 (6) that sums up to the smallest amount. The starting indice is not counted, thus, if I go from values[0] to values[1] (which is the only possible starting move), my running total at that point would be 10. From there, I either have the choice to "jump" back the same distance (to values[0]), or "jump" one distance longer than my last jump, which would then be 1+1=2, so jump from values[1] to values[3].
I'm really new to dynamic programming and attempted a solution that went something like this
public static int smallestCalc(int[] values, int prevJump, int pos, int runTot) {
while (pos != penal.length) {
int forwards = 600;
int backwards = 600;
try {
backwards = penal[pos - prevJump];
} catch (Exception ignore) {}
try {
forwards = penal[pos + prevJump+1];
} catch (Exception ignore) {}
int min = Math.min(forwards,backwards);
if (min == backwards) {
pos -= prevJump;
} else {
pos += prevJump + 1;
prevJump ++;
}
runTot+=min;
smallestCalc(values, prevJump, pos, runTot);
}
return runTot;
}
However, I recognize that I'm not actually making use of a dynamic programming table here, but I'm not exactly sure what I would store inside that I need to "remember" across calculations, or how I could even utilize it in calculations. From what I see, it appears that I basically have to make a recursive function that evaluates all possible jump distances from an index, store them, and then traverse through the DP table to find the smallest amount? Should I be starting from the last index or the first index of the array to limit possible moves? I watched this video here, and understood the premise, but it seems much more applicable to his 2D Array than anything I have. Any amount of guidance here would be greatly appreciated.
In my opinion, this is a 2D DP problem.
dp(i, j) represents the minimum sum required to reach last index from index i and minimum jump allowed of size j.
Let's say you are at index i in the array. Then you can either go to index i-j+1 or index i+j.
So,
int recur(int values[], int i, int j){
// base case. Here n is size of values array
if(i==n-1)
return 0;
if(dp[i][j] != -1){
/* here -1 is taken as to mark never calculated state of dp.
If the values[] array also contains negative values then you need to change it to
something appropriate.
*/
return dp[i][j];
}
int a = INT_MAX;
int b = a;
if(i>0 && (i-j+1)>=0)
a = values[i-j + 1] + recur(values, i-j+1, j);
if(i+j < n)
b = values[i+j] + recur(values, i+j, j+1);
return dp[i][j] = min(a, b);
}
Time and space complexity O(n * n).
Edit:
Initial function call is recur(values, 0, 1).
I know that the tag of this question is java but I do competitive programming in c++ only. Here I have full working code if you want in c++.

why does selection sort method start loop with "i = from + 1"

i am working with a selection short method to sort an array. the method starts its minimumPosition method with a for loop that starts with "i = from + 1". why does it start with that instead of "i = 0"?
can someone explain this for me please?
thanks!
edit: added context
/**
Finds the smallest element in a tail range of the array.
#param a the array to sort
#param from the first position in a to compare
#return the position of the smallest element in the
range a[from] . . . a[a.length - 1]
*/
private static int minimumPosition(int[] a, int from)
{
int minPos = from;
for (int i = from + 1; i < a.length; i++)
{
if (a[i] < a[minPos]) { minPos = i; }
}
return minPos;
}
}
The ocumentation already tells you why its i = from +1 and not i = 0. Documentation: Finds the smallest element in a tail range of the array.
Since the method finds the smallest element tailing from the loop only compares every element at the position from or greater. And since a[from] is the initial minimum you can start comparing at position from+1.

How to shift element in an Arraylist to the right in java

So I am trying to create a method that shifts all of the elements in an arraylist to the right and the last element will become the first element. When I run the code, I am told I have an out of bounds error. Here is what I have so far:
public void shiftRight()
{
//make temp variable to hold last element
int temp = listValues.get(listValues.size()-1);
//make a loop to run through the array list
for(int i = listValues.size()-1; i >= 0; i--)
{
//set the last element to the value of the 2nd to last element
listValues.set(listValues.get(i),listValues.get(i-1));
//set the first element to be the last element
listValues.set(0, temp);
}
}
Maybe this is an exercise you are working on, but the ArrayList.add(int index,E element) method does almost what you want.
"Inserts the specified element at the specified position in this list. Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices)." (italics added)
So just add the last element in the list at position 0. And delete it from the end.
A few problems here:
Your for loop condition needs to exclude the zeroth element so it should be i > 0 otherwise you'll get to the point where you want to put element at position -1 to position 0 resulting in out of bounds error.
Setting the first element to be the last should be outside the loop.
listValues.set takes in an index in the list as the first parameter, you are giving it the object in the list
public void shiftRight()
{
//make temp variable to hold last element
int temp = listValues.get(listValues.size()-1);
//make a loop to run through the array list
for(int i = listValues.size()-1; i > 0; i--)
{
//set the last element to the value of the 2nd to last element
listValues.set(i,listValues.get(i-1));
}
//set the first element to be the last element
listValues.set(0, temp);
}
The easiest and shortest solution : (if you don't have concurrent use of list - Because in concurrent use and iterating on it, the list size should not change, otherwise you get ConcurrentModificationException)
public void shiftOneToRight() {
listValues.add(0, listValues.remove(listValues.size() - 1));
}
Here is the simplest solution
Collections.rotate(list, rotationPosition);
my code to put a number in the right place in a List
int nr = 5; // just a test number
boolean foundPlace = false;
for(int i = 0; i < integerList.size(); i++){
if(nr <= integerList.get(i)){
integerList.add(i,nr);
foundPlace = true;
break;
}
}
if (!foundPlace)
integerList.add(integerList.size(), nr);
as the guy above said, "integerList.add(element)" inserts the specified element at the specified position in this list. Shifts the element currently...
input array list: locationMap
shift LHS elements from idxStart in circular way
shifted output list: extendedList
// make extended list to behave like circular
List<String> extendedList = new ArrayList<>();
for (int i = idxStart; i < locationMap.size(); i++) { // current to end
extendedList.add(locationMap.get(i));
}
for (int i = 0; i < idxStart; i++) { // 0 to current
extendedList.add(locationMap.get(i));
}

Binary/Sequential Searches

I'm trying to write a program that conducts a sequential search and a binary search in an array called items that has 10000 sorted random int values. A second array called targets is loaded with 1000 int values (500 values from the items array and 500 values that are not in the items array).
Basically, the search needs to go through the items array to look for int values in the targets array. This is my code:
import java.util.*;
// Loads two arrays with integers
// Searches the arrays using sequential search and binary search
// Compares the time for each search
public class Searches {
private int items[], targets[];
public Searches() {
this.items = new int[10000];
this.targets = new int[1000];
}
public void loadItemsAndTargets(){
int nextValue = 100;
int index = 0;
Random generator = new Random(1);
items[0] = nextValue;
/* load the items array with items to be searched through */
for (index = 1; index < items.length; index++){
nextValue = nextValue + generator.nextInt(100);
items[index]= nextValue;
}
/* load the targets array with target values that will be searched for within
* array items, and target values that are not within array items
*/
index = 0;
while (index < targets.length){
targets[index] = items[index*10];
targets[index+1] = generator.nextInt(100);
index = index + 2;
}
}
public int sequentialSearch(int target) {
/* Using the sequential search algorithm, search the items array for the target value passed
* If found, return the index in the items array, otherwise return -1
*/
this.loadItemsAndTargets();
int key = target;
int index;
boolean found = false;
index = 0;
while ((!found) && (index < items.length))
if (key == target)
found = true;
else
index = index + 1;
if (!found)
index = -1;
return index;
}
public int binarySearch(int target){
/* Using the binary search algorithm, search the items array for the target value passed
* If found, return the index in the items array, otherwise return -1
*/
this.loadItemsAndTargets();
target = targets.length;
int key = target;
boolean found = false;
int guess = 0;
int low = 0;
int high = items.length - 1;
while ((!found) && (low < high)) {
guess = (high+low)/2;
if (key == items[guess])
found = true;
else if (key < items[guess])
high = guess - 1;
else
low = guess + 1;
if (!found)
return - 1;
}
return guess;
}
public static void main(String[] args) {
int index = 0;
Searches searcher = new Searches();
searcher.loadItemsAndTargets();
/* call the method that searches array items
* for each of the values in array targets
* using the sequential search algorithm
* print the approximate elapsed time in milliseconds
* For the FIRST FIVE searches print out the index
* where target value was found or print -1 if it was not found
*/
long startTimeSequential;
startTimeSequential = System.currentTimeMillis();
System.out.println(searcher.sequentialSearch(index));
long endTimeSequential;
endTimeSequential = System.currentTimeMillis();
long totalTimeSequential;
totalTimeSequential = endTimeSequential-startTimeSequential;
System.out.println("sequential search time: " + totalTimeSequential + " milliseconds");
/* call the method that searches array items
* for each of the values in array targets
* using the binary search algorithm
* print the approximate elapsed time in milliseconds
* For the FIRST FIVE searches print out the index
* where target value was found or print -1 if it was not found
*/
long startTimeBinary;
startTimeBinary = System.currentTimeMillis();
System.out.println(searcher.binarySearch(index));
long endTimeBinary;
endTimeBinary = System.currentTimeMillis();
long totalTimeBinary;
totalTimeBinary = endTimeBinary - startTimeBinary;
System.out.println("binary search time: " + totalTimeBinary + " milliseconds");
}
}
EDIT: The output should be this >
395
986
-1
14
-1
sequential search time: 40 milliseconds
395
986
-1
14
-1
binary search time: 0 milliseconds
Your sequentialSearch is all wrong, you are not even accessing the array in it.
Both your search method call loadItemsAndTargets. It should only be called once
binarySearch only works on sorted array. Your arrays are not sorted.
Even if you correct all of these mistakes. Beware that your array will contain duplicates. So if try to compare the index between sequentialSearch and binarySearch they may not match unless your binarySearch returns the lower bound
Sometimes it is easier to write the code when you have a very strong grasp of the searching techniques at hand. With that in mind, I'll repeat what you probably have heard just in case it wasn't explained well.
A sequential search is simple:
1. Set the starting index just before the beginning.
2. If there is a "next" item, check the next item to see if it matches.
2a. If it does match you found the item in your collection.
2b. If it does not match update the starting index to the item you just checked and continue at step 2.
3. If there is no next item, then you searched everything without finding your item.
A binary search is also simple:
1. If the unsearched part of your list is empty, then determine you didn't find the item.
2. If the unsearched part of your list is just one element, then check the element to see if it matches the lookup item.
2a. If id does match, you found the item in your list.
2b. If it does not match, the item isn't in your list.
3. If the unsearched part of your list is more than one element, find the element closest to the middle. It is ok to divide two element lists like {2, 4} into {2} 4 {} where 4 is the middle.
3a. If the middle matches the lookup item, you found the item in your list.
3b. If the middle is larger than the lookup item, select the "smaller" side list and repeat the process.
3c. If the middle is smaller than the lookup item, select the "larger" side list and repeat the process.
The advantage of a sequential search is that your item will eventually be found, even if the list is not sorted. The advantage of a binary search is that you will find your item much faster but the list must be sorted. For example, a million item list will take on average half a million comparisons to find an item by sequential search; but, a binary search will take only about twenty comparisons. That is because each comparison in a binary search throws away half of the remaining possibilities while each comparison in a sequential search only throws away one possibility.

Categories

Resources