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.
Related
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>>)
There are no errors but it still won't work. I can't figure out what's wrong. We still haven't discussed the concept of nodes in class so I have trouble understanding it.
It's output should be:
Skinny Love- Birdy
Happier- Ed Sheeran
Someday- Chelsea Cutler
public class HandsOnAct1 {
static LinkedList songs = new LinkedList();
static LinkedList artists = new LinkedList();
static LinkedList playlist = new LinkedList();
public static void Merge(){
int element= songs.size();
int number=0;
System.out.println(element);
if (number !=element){
playlist.add(number, songs);
playlist.add(number,artists);
number++;
}
System.out.println(playlist);
}
public static void main(String[] args) {
songs.add("Skinny Love");
songs.add("Happier");
songs.add("Sometimes");
artists.add("Birdy");
artists.add("Ed Sheeran");
artists.add("Chelsea Cutler");
Merge();
}
}
Here is an example using recursion as i understand it was a pre-requisite?
static LinkedList<String> songs = new LinkedList<>();
static LinkedList<String> artists = new LinkedList<>();
static LinkedList<String> playlist = new LinkedList<>();
songs.add("Skinny Love");
songs.add("Happier");
songs.add("Sometimes");
artists.add("Birdy");
artists.add("Ed Sheeran");
artists.add("Chelsea Cutler");
int index = 0;
static void merge() {
// if you want/need checks
if ( index >= artists.size()){
return;
}
playlist.add(songs.get(index) + " - " + artists.get(index));
System.out.println(playlist.get(index));
index++;
merge();
}
merge();
the main issue with your own code is that you need to call merge again from inside it and either move the index outside the function as i have done or take it in as a parameter like public static void merge(int index). you will then call it from inside like merge(index++).
That's a matter of opinion i guess. (if you want you can read on pure/impure functions and imperative/functional programming which is the difference)
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 am doing homework. I would like to build a base case for a recursion where ordering given numbers (list2) in ascending order. Purpose of writing this codes is that when all numbers are in ascending order then should stop calling a method called ascending(list2, list1); and all values in list2 should be shipped to list1. For instance, list2 = 6,5,4,3,2,1 then list2 becomes empty and list1 should be 1,2,3,4,5,6. I am trying to compare result with previous one and if matches then stop. But I can't find the base case to stop it. In addition, Both ascending() and fixedPoint() are void method. Anybody has idea? lol Took me 3 days...
When I run my code then
6,5,4,3,2,1
5,6,4,3,2,1
4,5,6,3,2,1
3,4,5,6,2,1
2,3,4,5,6,1
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
infinite.............
public class Flipper
{
public static void main(String[] args)
{
Flipper aFlipper = new Flipper();
List<Integer> content = Arrays.asList(6,5,4,3,2,1);
ArrayList<Integer> l1 = new ArrayList<Integer>(content);
ArrayList<Integer> l2 = new ArrayList<Integer>(); // empty list
aFlipper.fixedPoint(l2,l1);
System.out.println("fix l1 is "+l1);
System.out.println("fix l2 is "+l2);
}
public void fixedPoint(ArrayList<Integer> list1, ArrayList<Integer> list2)
{
// data is in list2
ArrayList<Integer> temp1 = new ArrayList<Integer>(); // empty list
if (temp1.equals(list2))
{
System.out.println("found!!!");
}
else
{
ascending(list2, list1); // data, null
temp1 = list1; // store processed value
System.out.println("st list1 is "+list1);
System.out.println("st list2 is "+list2);
}
fixedPoint(list2, list1); // null, processed data
}
Second try after receiving advice.
else {
temp1 = list2;
System.out.println("temp1: "+temp1);
// temp1 printed out the value assigned
// store only previous value
ascending(list2, list1); // data, null
temp2 = list1;
// store previous value
System.out.println("temp1: "+temp1);
// after invoking ascending() temp1
becomes empty lol So not able to compare in if statement....
Can anybody correct it?
System.out.println("temp2: "+temp2);
}
fixedPoint(list2, list1); // previous, proceeded data
After brain storming with dasblinkenlight, Julien S, Nikolas, ZouZou and vels4j a solution found. I appreciate your contribution of thought! :-)
public void fixedPoint(ArrayList<Integer> list1,
ArrayList<Integer> list2)
{
List<Integer> content = Arrays.asList(1);
ArrayList<Integer> temp1 = new ArrayList<Integer>(content);
fixedPoint(list2, list1, temp1);
}
// Since it is recursive method I needed to create another parameter
// to store temporary values.
public void fixedPoint(ArrayList<Integer> list1,
ArrayList<Integer> list2,
ArrayList<Integer> temp)
{
ArrayList<Integer> temp1 = new ArrayList<Integer>();
temp1 = temp;
if (temp1.equals(list2))
{
return;
}
else
{
temp1.clear();
for(int i = 0; i < list2.size(); i++)
// To store temp value of list2,
// I used add method. Because ArrayList is an object type so if I assign
// list2 to temp1 then it will assign memory address rather
// than values. Thus I will lose the values after invoking ascending() as
// all elements of list2 will shipped to list1. So List2 becomes empty.
{
temp1.add(list2.get(i));
}
ascending(list2, list1);
fixedPoint(list2, list1, temp1);
}
}
Purpose of writing this codes is that when all numbers are in ascending order then should stop calling a method called ascending(list2, list1)
Then you should add a loop that checks for the elements of list1 to be in ascending order, like this:
public void fixedPoint(ArrayList<Integer> list1, ArrayList<Integer> list2)
{
boolean isAscending = true;
for (int i = 1 ; (isAscending) && (i < list2.size()) ; i++) {
isAscending = list2.get(i-1) < list2.get(i);
}
if (isAscending) {
... // Insert code to copy the data from list2 to list1.
... // Note that a simple assignment is not going to work here!
System.out.println("found!!!");
return;
}
// It's not in ascending order - continue recursing down.
ascending(list2, list1);
ArrayList<Integer> temp1 = new ArrayList<Integer>(list1); // store processed value
fixedPoint(list2, list1);
// temp1 makes the old value of list1 available for comparison
System.out.println("st list1 is "+list1);
System.out.println("st list1 was "+temp1);
System.out.println("st list2 is "+list2);
}
There is no return in fixedPoint when the case is found. Therefore the line fixedPoint(list2, list1);
will be processed regardless of the fixed point.
I am not able to test since ascending method is not provided, however I think that
if (CollectionUtils.isEqualsCollection(list1,list2)
{
System.out.println("found!!!");
return;
}
would do the job.
You will require Apache-commons Collections to perform the equality on lists with isEqualsCollection.
Your problem probably arises from the usage of temp1.equals(list2). What you want to use is Arrays.equals(temp1, list2).
An explanation for this is given here by Peter Lawrey.
Edit
Yeah, I should probably read better.
I just checked and it appears ArrayList inherits .equals() from List which is defined differently than array.equals() and "should" work.
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!