I recently watched a dynamic programming tutorial on Youtube explaining dynamic programming but the Tutor solved problems in JavaScript. I, on the other hand, use Java for data structures and algorithms. While implementing dynamic programming to solve a question. I discovered that I got the solution to the problem when using int[] but had wrong answer when using ArrayList<Integer> because somehow, the ArrayList already stored in the HashMap was being modified internally.
Question:
Write a function bestSum(targetSum, numbers) that takes in a targetSum and an array of numbers as arguments and returns an array containing the shortest combination of numbers that add up to exactly the target sum.
Example:
bestSum(7,new int[]{2,1,3}) => [3,3,1] //other possibilities but not answer:[2,2,2,1], [1,1,1,1,1,1,1], [2,2,1,1,1], etc
bestSum(100,new int[]{2,5,25}) => [25,25,25,25]
Code using int[]:
public class Persist {
public static HashMap<Integer,int[]> memo = new HashMap<>();
public static int[] bestSum(int n, int[] arr){
if(memo.containsKey(n)){
//System.out.printf("From memo: %d->"+ Arrays.toString(memo.get(n)) +"%n",n);
return memo.get(n);
}
if(n==0)return new int[0];
if(n<0)return null;
int[] minn = null;
for(int i = 0;i<arr.length;i++){
//recursion
var temp = bestSum(n-arr[i],arr);
if(temp!=null){
// ttemp is used to add arr[i] to the initial arr <<temp>>
int[] ttemp = new int[temp.length+1];
System.arraycopy(temp,0,ttemp,0,temp.length);
ttemp[temp.length] = arr[i];
temp = ttemp;
if(minn==null||temp.length<minn.length){
minn = temp;
}
}
}
//System.out.println(n+": "+minn);
memo.put(n,minn);
//System.out.println(memo.get(n));
return minn;
}
public static void main(String[] args){
System.out.println(Arrays.toString(bestSum(7, new int[]{2,1,3})));
}
}
Code using ArrayList<Integer> :
public class Persist {
public static HashMap<Integer,ArrayList<Integer>> memo = new HashMap<>();
public static ArrayList<Integer> bestSum(int n, int[] arr){
if(memo.containsKey(n)){
//System.out.printf("From memo: %d->"+ memo.get(n)+"%n",n);
return memo.get(n);
}
if(n==0)return new ArrayList<>();
if(n<0)return null;
ArrayList<Integer> minn = null;
for(int i = 0;i<arr.length;i++){
var temp = bestSum(n-arr[i],arr);
if(temp!=null){
temp.add(arr[i]);
if(minn==null||temp.size()<minn.size()){
minn = temp;
}
}
}
//System.out.println(n+": "+minn);
memo.put(n,minn);
//System.out.println(memo.get(n));
return minn;
}
public static void main(String[] args){
System.out.println(bestSum(7,new int[]{2,1,3}));
}
}
The only differences between the two code snippets is the use of int[] and ArrayList<Integer> respectively, but one works and the other doesn't. I will like to know why, thanks.
Link to Youtube explanation of bestSum()
It's easy to get caught up with memoization and dynamic programming and forget that about pass by reference and pass by value. The key difference here to remember is that ArrayList is pass by reference.
If you debug and look at your hashmap memo, you see that the sizes of the int[] only reaches up to 3, whereas in the arraylist hashmap most of the values has a size of 7
I had a similar problem: casting does not work on nested list object type and returns empty lists (List<List<Integer>>)
Related
Just out of curiosity, based on that code is there a way to that instead of
int [][]d = { obj[0].ar , obj[1].ar , obj[2].ar };
can be written under a for like this
for(int i=0;i<obj.ar.length;i++)
or to just combine all arrays of obj[].ar using obj.length in one 2 dimenstional array?
public class Main
{
public static void main(String[] args)
{
int nb = 3;
arr[] obj = new arr[nb];
for(int i=0;i<obj.length;i++)
{
obj[i] = new arr(i+2);
}
int [][]d = { obj[0].ar , obj[1].ar , obj[2].ar };
for(int i=0;i<d.length;i++)
{
for(int j=0;j<d[i].length;j++)
System.out.print(d[i][j]+"\t");
System.out.println();
}
}
}
class arr
{
int []ar;
arr(int nb)
{
ar = new int[nb];
for(int i=0;i<ar.length;i++)
ar[i]=i;
}
}
Java arrays must always have a determined size upon creation.
Notice you are always setting nb in the calls to new arrays, or by using the {} instantiator which will count the number of objects statically.
What you are asking for is probably what ArrayList is meant to achieve. It will grow as you go, while having an array implementation behind the scenes. If the contents cannot fit in the array, a new - larger - array is created to fit them all. You won't notice this while using it though.
ArrayList<ArrayList<Integer>> obj = new ArrayList<>();
obj.add(new ArrayList<>());
obj.add(new ArrayList<>());
obj.add(new ArrayList<>());
// There are now three empty lists, in the main list.
Since java 9, you can use some extra helper methods:
List<List<Integer>> obj = List.of(
List.of(1,2,3),
List.of(2,3,4)
);
If you want, you can implement you own ArrayList class, it's not that hard!
It's my first question here so apologies in advance if i miss any guideline.
i am working on binary search tree for learning purpose for past 3 days and i am stuck with one issue for a day now. tried to debug it as much as i can. Also tried to search on internet to see if there is any help but no success.
i have 3 classes
main class
bst class
integerset class
integerset has this constructor
public IntegerSet(int arr[])
{
this.bst1 = new BST();
for (int i = 0; i < arr.length; i++) {
this.bst1.insert(arr[i]);
this.magnitude = this.bst1.getSize();
}
}
which create bst object and insert array elements to bst.
when i do this from main
int[] arr = {1,2,3,4,5};
iSet = new IntegerSet(arr);
it works all fine, but when i create another object
int[] arr2 = {4,5,6,7};
iSet2 = new IntegerSet(arr2);
after creation of 2nd object both has same bst in them which contains 2nd array.
been trying to solve this but doesn't understand why this is happening both should have their own integer-set object with their own bst.
Do check implementation of IntegerSet. It should be like this:
class IntegerSet {
private final BST bst = new BST();
private int magnitude;
public IntegerSet(int[] arr) {
for(int val : arr)
bst.insert(val);
magnitude = bst.getSize();
}
}
In this method I am trying to create an array from a file I passed into the method (the file has a list of numbers) and then I want to return the array. But when I try to run my code the error pops up that it can't find the symbol "nums".
I'm positive I have a scope problem, but I do not know how to fix this.
How do I fix this code so that it will return the array correctly?
Here is my code:
//reads the numbers in the file and returns as an array
public static int [] listNumbers(Scanner input) {
while (input.hasNext()) {
int[] nums = new int[input.nextInt()];
}
return nums;
}
You have at least two problems here.
Firstly, nums is defined inside your while loop, and it goes out of scope when you exit the loop. This is the cause of your compilation error. You'd need to move the definition outside of your loop if you want to return it once the loop has finished.
However, there's another problem, which is that you don't know how big your array needs to be until you've read the whole file. It would be much easier to create an ArrayList<Integer> and add elements to it, and then convert this to an array (if necessary) once you've read the whole file. Or just return the list, rather than an array.
public static List<Integer> listNumbers(Scanner input) {
List<Integer> nums = new ArrayList<Integer>();
while (input.hasNext()) {
nums.add(input.nextInt());
}
return nums;
}
List<Integer> list = new ArrayList<Integer>();
while(input.hasNext())
{
list.add(input.nextInt());
}
int size = list.size();
int[] nums = new int[size];
int counter = 0;
for(Integer myInt : list)
{
nums[counter++] = myInt;
}
return nums;
This solution is not tested, but can give you some direction. It's also along the lines of what Simon is referring to as well.
I have this simple program to compute all the subsets of a given set.
The algorithm, I believe is correct.
However in part:
while (included.size()>0){
ArrayList<Integer> temp =included.remove(0);
temp.add(first_element);
output.add(temp);
}
the statement temp.add(first_element) is unnecessarily updating not_included.
Please help me understand why.
public class Recursion {
public static ArrayList<ArrayList<Integer>> getSubsets (ArrayList<Integer> input_set){
ArrayList<ArrayList<Integer>> output=new ArrayList<ArrayList<Integer>>();
if (input_set.isEmpty()){
ArrayList<Integer> this_subset=new ArrayList<Integer>();
output.add(this_subset);
}
else if (input_set.size()==1){
ArrayList<Integer> empty_subset=new ArrayList<Integer>();
output.add(input_set);
output.add(empty_subset);
}
else{
int first_element=input_set.remove(0);
ArrayList<ArrayList<Integer>> included = getSubsets(input_set);
ArrayList<ArrayList<Integer>> not_included = getSubsets(input_set);
while (included.size()>0){
ArrayList<Integer> temp =included.remove(0);
temp.add(first_element);
output.add(temp);
}
while (not_included.size()>0){
output.add(not_included.remove(0));
}
}
return output;
}
public static void main(String[] args) {
ArrayList<Integer> test= new ArrayList<Integer> ();
test.add(2);
test.add(1);
System.out.print(getSubsets(test));
}
}
Try
ArrayList<ArrayList<Integer>> not_included = getSubsets(input_set.clone());
This might still not work though since your generic type of the array list is also an array list. Search for "deep copying" to find a 100% working solution.
getSubSet only returns a pointer to the same list since the parameter is the same, that's why included and not_included are the same lists.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to create ArrayList (ArrayList<T>) from array (T[]) in Java
How to implement this method:
List<Integer> toList(int[] integers) {
???
//return Arrays.asList(integers); doesn't work
}
There's probably a built-in method to do it somewhere* (as you note, Arrays.asList won't work as it expects an Integer[] rather than an int[]).
I don't know the Java libraries well enough to tell you where that is. But writing your own is quite simple:
public static List<Integer> createList(int[] array) {
List<Integer> list = new ArrayList<Integer>(array.length);
for (int i = 0; i < array.length; ++i) {
list.add(array[i]);
}
return list;
}
Obviously one downside of this is that you can't do it generically. You'll have to write a separate createList method for each autoboxed primitive type you want.
*And if there isn't, I really wonder why not.
Use commons-lang3 org.apache.commons.lang3.ArrayUtils.toObject(<yout int array>) and then java.util.Arrays.asList(<>)
ArrayUtils.toObject() will copy the array, and Array.asList() will simply create list that is backed by new array.
int[] a = {1, 2, 3};
List<Integer> aI = Arrays.asList(ArrayUtils.toObject(a));
EDIT: This wont work if you want to add() new elements (resize) though the list interface, if you want to be able to add new elements, you can use new ArrayList(), but this will create one more copy.
List<Integer> asList(final int[] integers) {
return new AbstractList<Integer>() {
public Integer get(int index) {
return integers[index];
}
public int size() {
return integers.length;
}
};
}
List<Integer> toList(int[] integers) {
// Initialize result's size to length of the incoming array
// this way it will not require reallocations
ArrayList<Integer> result = new ArrayList<Integer>( integers.length );
for ( int cur: integers )
{
result.add( Integer.valueOf( cur ) );
}
return result;
}
I do not think there is a quick way to do it unfortunately. I believe you will have to iterate the array and add it one by one.
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class Listing {
public static void main(String[] args) {
int[] integers = {1,2,3,4};
java.util.List<Integer> list = new ArrayList<Integer>();
for (int i=0; i< integers.length; i++)
{
list.add(integers[i]);
}
System.out.println(list);
}
}
Tested and working as expected!