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));
}
Related
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);
}
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
i got this problem where i need to return the line which its members bring the biggest sum in matrix, the problem needs to be with recursive methods ( no loops )
i started firstly by finding the biggest sum, but i dont know how to proceed further, please help me
public class MatrixLen {
private int [][] _mat;
public MatrixLen(int sizeRow, int sizeCol)
{
_mat = new int[sizeRow][sizeCol];
Random generator = new Random();
for (int i = 0; i< sizeRow; i++){
for (int j=0; j<sizeCol; j++){
_mat[i][j] = generator.nextInt(20) - 10;
System.out.print(_mat[i][j]+ " ");
}
System.out.println();
}
}
private int SumRow(int i){
return SumRow(i,0);
}
private int SumRow(int i, int j){
if(j>=_mat[i].length) return 0;
return _mat[i][j] + SumRow(i, j+1);
}
public int maxRow(){
if(_mat.length==0) return -1;
return maxRow(0);
}
private int maxRow(int i){
if (i == _mat.length - 1) return SumRow(i); //end case - last row
int max = maxRow (i + 1);
int thisRow = SumRow(i);
return thisRow > max ? thisRow : max;
}
}
You can define a class holding the index of the current row as well as the sum. E.g.
public class IndexSum {
int index;
int sum;
public IndexSum(int index, int sum) {
this.index = index;
this.sum = sum;
}
}
Then in MatrixLen modify maxRow methods to get as argument and also return a IndexSum object. This way, during recursion, you keep track of the sum of a row to compare with other rows, but also of the index of this row.
public IndexSum maxRow() {
if (_mat.length == 0) return null;
return maxRow(new IndexSum(0, SumRow(0)));
}
private IndexSum maxRow(IndexSum thisRow) {
if (thisRow.index == _mat.length - 1) return thisRow; //end case - last row
IndexSum nextRow = maxRow(new IndexSum(thisRow.index + 1 , SumRow(thisRow.index + 1)));
return thisRow.sum > nextRow.sum ? thisRow : nextRow;
}
Are member fields accepted ?
int index = -1;
private int maxRow(int i) {
if (i == _mat.length - 1) {
index = i;
return SumRow(i); // end case - last row
}
int max = maxRow(i + 1);
int thisRow = SumRow(i);
if (thisRow > max) {
index = i;
}
if (i == 0) {
return index;
}
return thisRow > max ? thisRow : max;
}
I have written a sorted vector which works fully. However my Add method is very long and I feel like there is a lot of redundant code.
I have a binary search function written and I would like to use this in my Add method instead of doing comparisons in the Add function also.
Below is my code:
public class SortedVector
{
private int maxcap = 10, noOfItems = 0, grow = 10;
private String[] data = new String[maxcap];
// Default Constructor
public SortedVector()
{
}
public void SetGrowBy(int growby)
{
grow = growby;
}
public int GetCapacity()
{
return maxcap;
}
public int GetNoOfItems()
{
return noOfItems;
}
public String GetItemByIndex(int index)
{
if (index > noOfItems+1 || index < 0)
{
return null;
}
else
{
String item = data[index];
return item;
}
}
public int FindItem(String search)
{
int low=0;
int high = noOfItems - 1;
return binarySearch(search, low, high);
}
public int binarySearch(String search, int low, int high)
{
if(low>high)
return -1;
int mid = (low + high)/2;
if (data[mid] == search)
return mid;
else
if (data[mid].compareToIgnoreCase(search)<0)
return binarySearch(search, mid+1, high);
else
return binarySearch(search, low, mid-1);
}
public void AddItem(String value)
{
int thirdCounter = 0;
int fourthCounter = 0;
int place3= 0;
int place4 =0;
if(maxcap > noOfItems)
{
if(noOfItems == 0)
{
data[0] = value;
noOfItems++;
}
else
{
int firstCounter = noOfItems;
for (int i=0; i < firstCounter; i++)
{
String[]temp = new String[maxcap];
if(thirdCounter == 0)
{
if (data[i].compareToIgnoreCase(value)>0)
{
for (int j=0; j < noOfItems; j++)
{
temp[j+1] = data[j];
}
data=temp;
data[0] = value;
noOfItems++;
thirdCounter++;
}
else
{
if(data[i].compareToIgnoreCase(value)<0)
{
for (int j=0; j < noOfItems; j++)
{
if (data[j].compareToIgnoreCase(value)>0)
{
if(fourthCounter ==0)
{
temp[j+1] = data[j];
place3 = j;
fourthCounter++;
}
else
{
temp[j+1] = data[j];
}
}
else
{
temp[j]=data[j];
place4 = j;
}
}
if (place3 == 0)
{
if(place4 == 0)
{
data=temp;
data[1] = value;
noOfItems++;
firstCounter++;
}
else
{
data=temp;
data[place4+1] = value;
noOfItems++;
thirdCounter++;
}
}
else
{
data=temp;
data[place3] = value;
noOfItems++;
thirdCounter++;
}
}
}
}
}
}
}
else
{
int firstCounter = 0;
maxcap = grow +maxcap;
String[]temp3 = new String[maxcap];
for (int i=0; i < noOfItems; i++)
{
if(firstCounter == 0)
{
if (data[i].compareToIgnoreCase(value)>0)
{
for (int j=0; j < noOfItems; j++)
{
temp3[j+1] = data[j];
}
data=temp3;
data[0] = value;
noOfItems++;
firstCounter++;
}
else
{
int place1 = 0;
int place2 = 0;
int secondCounter = 0;
if(data[i].compareToIgnoreCase(value)<0)
{
for (int j=0; j < noOfItems; j++)
{
if (data[j].compareToIgnoreCase(value)>0)
{
if(j/2!=0 && secondCounter ==0)
{
temp3[j+1] = data[j];
place1 = j;
secondCounter++;
}
else
{
temp3[j+1] = data[j];
}
}
else
{
temp3[j]=data[j];
place2 = j;
}
}
if (place1 == 0)
{
if(place2 == 0)
{
data=temp3;
data[1] = value;
noOfItems++;
firstCounter++;
}
else
{
data=temp3;
data[place2+1] = value;
noOfItems++;
firstCounter++;
}
}
else
{
data=temp3;
data[place1] = value;
noOfItems++;
firstCounter++;
}
}
}
}
}
}
System.out.println("adding: "+value);
}
public void DeleteItem(int index)
{
if (index < noOfItems && index >= 0)
{
data[index] = null;
if (data[index+1] != null)
{
int j = index;
for(int i = (index+1); i<noOfItems; i++)
{
data[j] = data[i];
j++;
}
}
noOfItems--;
}
System.out.println("deleted: "+index);
}
public String toString()
{
return super.toString();
}
}
Any tips on how I could do that much appreciated.
Kind Regards,
Ben.
Implementing the add, (binaryAdd) is almost identical to how you implemented the binary search. The code will be 99% similar.
Let say you have the following data:
+--------------------------+
|10|20|30|40|50|60|70|80|90|
+--------------------------+
You want to add 35 into it and keep the data in ascending order.
The mid value is 50, and since 35 is < 50, we are interested in 10 to 50:
+--------------+
|10|20|30|40|50|
+--------------+
The mid value is 30, and since 35 is > 30, we are interested in 30 to 50:
+--------+
|30|40|50|
+--------+
The mid value is 40, and since 35 is < 40, we are interested in 30 to 40:
+-----+
|30|40|
+-----+
When you left with 2 elements, choose either left or the right for comparison:
if you choose left, 35 > 30, so 35 should be added after 30.
if you choose right, 35 < 40, so 35 should be before after 40.
The process is similar to binary search, but instead of returning the position of the target value, you return the position to insert the value.
Here it is
DEMO: https://repl.it/Eqak/0
public void AddItem(String value)
{
// Check if cursor at last
if(noOfItems + 1 == maxcap){
// Resize data
maxcap *= 2;
String[] newData = new String[maxcap];
System.arraycopy(data, 0, newData, 0, noOfItems);
data = newData;
}
// find the last element according to value
int idx = 0;
for(; idx<noOfItems; idx++){
if(data[idx].compareToIgnoreCase(value) >= 0) {
break;
}
}
// move elements if required
if(idx < noOfItems){
System.arraycopy(data, idx, data, idx+1, noOfItems-idx);
}
// set element on index
data[idx] = value;
noOfItems++;
System.out.println("adding: "+value);
}
The easiest way is make the binarySearch return the insertion position if the element is not found. Very much like Arrays.binarySearch does:
returns: index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1)
So, if the return of the ret=binarySearch is negative, you only need to take -ret-1 to get the insert position.
You can even take a look to the code, its open source anyway (i.e. not only it runs, but you can use it to learn from it)
(no, I won't copy/paste that piece of code; link-only answer - take it or leave it).
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;
}