Shortest subset sum of arr dynamic programming - java

My goal is to find the shortest subset of an array that its sum is equal to target. I tried to use the following solution (with dynamic programming):
public static List<Integer> bestSum_efficient(int targetSum, int[] numbers) {
return bestSum_efficient(targetSum, numbers, new HashMap<>());
}
public static List<Integer> bestSum_efficient(int targetSum, int[] numbers, Map<Integer, List<Integer>> map) {
if (map.containsKey(targetSum)) {
return map.get(targetSum);
}
if (targetSum == 0)
return new ArrayList<>();
if (targetSum < 0)
return null;
List<Integer> shortestCombination = null;
for (int n : numbers) {
List<Integer> remainedCombination = bestSum_efficient(targetSum - n, numbers,map);
if (remainedCombination != null) {
remainedCombination.add(n);
if (shortestCombination == null || shortestCombination.size() > remainedCombination .size()) {
shortestCombination = remainedCombination ;
}
}
}
map.put(targetSum, shortestCombination);
return shortestCombination;
}
With this code I tried to run the following test:
System.out.println(bestSum_efficient(8, new int[]{1, 4, 5})); // [4,4]
I got: [4,1,4]
When I changed the content of the first if to the following, everything worked fine:
for (int n : numbers) {
List<Integer> remainedCombination = bestSum_efficient(targetSum - n, numbers,map);
if (remainedCombination != null) {
List<Integer> combination = new ArrayList<>();
combination.add(n);
combination.addAll(remainedCombination);
if (shortestCombination == null || shortestCombination.size() > combination.size()) {
shortestCombination = combination;
}
}
}
Why does creating a new combination list each in each iteration worked, while using the remainingCombination list that returned didn't?

After squeezing my brain for a while, I think that I have found the root cause of this issue.
In the first scenario:
List<Integer> remainedCombination = bestSum_efficient(targetSum - n, numbers,map);
if (remainedCombination != null) {
remainedCombination.add(n);
We modify directly the list remainedCombination by adding n at the end of it. This will actually modify the entry of the HashMap that we use for memoization, when the function bestSum_efficient returns the saved entry via the lines:
if (map.containsKey(targetSum)) {
return map.get(targetSum);
}
as in this situation remainedCombination will be a reference to map.get(targetSum), so doing remainedCombination.add(n); is the equivalent of doing map.get(targetSum).add(n);
However we only want to modify the entries of the HashMap at the end of the bestSum_efficient function if we find a shortest way to reach the target sum and not directly in the for loop before checking the length condition if (shortestCombination == null || shortestCombination.size() > remainedCombination .size()) {
In the 2nd (working) example, we create a new temporary ArrayList
List<Integer> combination = new ArrayList<>();
combination.add(n);
combination.addAll(remainedCombination);
before adding n there. This will therefore not affect the HashMap used for the memoization, that will only be modified just before the return of the function:
map.put(targetSum, shortestCombination);
return shortestCombination;

Related

Getting wrong answer while trying to solve Best sum problem using Dynamic programming

Trying to solve the best sum problem but I'm not getting the right answer using DP but if I remove the memoization part of this code then I'm getting the right answer.
I'm attaching the output screenshots:
PS: Please do not judge my code I'm trying to learn DP and I know that this code is not the best.
public class BestSum {
public static void main(String[] args) {
int[] arr = { 2, 3, 4, 5 };
int num = 10;
Map<Integer, List<Integer>> map = new HashMap<>();
List<Integer> list = rec(arr, num, map);
System.out.println(list);
}
static List<Integer> rec(int[] arr, int n, Map<Integer, List<Integer>> map) {
if (n == 0) {
return new ArrayList<>();
}
if (n < 0) {
return null;
}
if (map.containsKey(n)) {
return map.get(n);
}
List<Integer> sCombo = null;
for (int i : arr) {
int rem = n - i;
List<Integer> t = rec(arr, rem, map);
if (t != null) {
List<Integer> list = new ArrayList<>();
t.add(i);
list.addAll(t);
if (sCombo == null || list.size() < sCombo.size()) {
sCombo = list;
}
}
}
map.put(n, sCombo);
return map.get(n);
}
}
list.add(i); // write this instead of t.add(i).
a little mistake in the code nothing else.
just small mistake i.e....
you directly inserting sCombo into the Map. the values in sCombo array was changing while recursion every time at the same time the same sCombo array values in the map also changing because there have only one block of memory for each sCombo array that means when ever we edit that sCombo array it will effects the previous result....
example:- you assigned the list to sCombo
sCombo=list;
when ever the list gets changes then the sCombo also changed
just clone() the object you get correct result like this......

How to print the index of an array into separate ArrayList

I have created a method for my program, where I compare two arrays, user and test. I am trying to add the index of the array user into the ArrayList qMissed when it is not the same as the test Array.
If both arrays are the exact same then it should just return null.
I am getting exception errors because I need to complete the reference type but I am unsure of what to do.
/**
* #param user
* #param test
* #return
*/
public static ArrayList<String> questionMissed(String[] user, String[] test)
{
ArrayList<int> qMissed = new ArrayList<int>();
for (int i = 0; i <= user.length-1; i++)
{
if (user[i] != test[i])
{
qMissed = Arrays.asList(qMissed).indexOf(user);(i+1);
}
else if (user[i] == test[i])
{
return null;
}
}
return qMissed;
}
Your method seems to have some logical and compilation issues.
Looks like you need this method,
public static List<Integer> questionMissed(String[] user, String[] test) {
List<Integer> qMissed = new ArrayList<Integer>();
for (int i = 0; i < user.length; i++) {
if (!user[i].equals(test[i])) {
qMissed.add(i);
}
}
return qMissed.size() == 0 ? null : qMissed;
}
Fixes and their explanation,
1. Your return type has to be List<Integer> instead of ArrayList<String> because you want to return an ArrayList of Integer indexes and not string.
2. Second problem you can't use primitive type in ArrayList<int> instead you need to use ArrayList<Integer>
3. You can't compare strings with == instead you need to use equals method on string.
4. You don't have to return null inside forloop else hence else block I have removed.
5. After you exit the forloop, as you want to return null if both element's arrays matched hence this code,
return qMissed.size() == 0 ? null : qMissed;
Let me know if you face any issues using this method.
Edit:
How to display "All are correct" message in case both passing arrays have same numbers. You must be calling it something like this,
List<Integer> list = questionMissed(user,test);
if (list == null) {
System.out.println("All are correct");
} else {
// your current code
}
You can try changing the return type from ArrayList to ArrayList in the method:
public static ArrayList<int> questionMissed(String[] user, String[] test) {
ArrayList<int> qMissed = new ArrayList<int>();
for (int i=0;i<=user.length-1;i++) {
if (user[i] != test[i]) {
qMissed = Arrays.asList(qMissed).indexOf(user);(i+1);
} else {
return null;
}
}
return qMissed;
}
Also you can remove the else if condition cause is redundant. Please attach the exceptionsyou are getting.
I see multiple issues with your code, Firstly as Andreas said ArrayList cannot host primitive types
so change it to
ArrayList<Integer> qMissed = new ArrayList<Integer>();
Second problem I see is that you are comparing Strings using == this compare can be wrong so use equals instead
(user[i].equals(test[i]))
and the last mistake I see is the code cannot be compiled, can you give me more information in the comments to what you are trying to do in this part since It's not valid code
qMissed = Arrays.asList(qMissed).indexOf(user);
(i + 1);
if you want to do something like Pushpesh Kumar Rajwanshi answer you can use java 8 streams what this does is makes an IntStream with the length of user, and then filters it to have only items if they don't equal at the same index and then adds it to qMissed.
public static List<Integer> questionMissed(String[] user, String[] test) {
List<Integer> qMissed = new ArrayList<>();
IntStream.range(0, user.length)
.filter(i -> !user[i].equals(test[i]))
.forEach(qMissed::add);
return qMissed.size() == 0 ? null : qMissed;
}
I guess you want like below ..
public static ArrayList<Integer> questionMissed(String[] user, String[]
test) {
ArrayList<Integer> qMissed = new ArrayList<Integer>();
int i = 0;
if(user.length == test.length ) {
while(i < user.length ){
if (!(user[i].equals(test[i]))) {
qMissed.add( i + 1);
}else {
return null;
}
i++;
}
if(user.length > 0 && i == user.length ) {
return qMissed;
}
}
return null;
}

Remove all the odd numbers in an ArrayList

I already wrote code to remove all the odd numbers in an ArrayList.
import java.util.*;
public class Odd {
public static void main (String [] args) {
ArrayList <Integer> mylist = new ArrayList<>(Arrays.asList(1, 2, 4, 6, 7));
System.out.println(odd(mylist));
}
public static int odd(ArrayList<Integer> list) {
if (list.isEmpty()) { throw new Error(); }
int a = list.get(0);
List<Integer> toRemove = new ArrayList<>();
for (int si : list) {
if (si % 2 != 0) { toRemove.add(si); }
}
list.removeAll(toRemove);
return a;
}
}
But somehow the result is always 1.Can someone point out what is my mistake?Thank you in advance
There are two problems with your code:
(1) You need to return the list object (contains Integers) after the removal of odd numbers
(2) In order to return the list, you need to change the method signature from int to List<Integer> (as return type):
You can refer the below code with comments:
//change the method signature to return List<Integer>
public static List<Integer> odd(ArrayList<Integer> list) {
if (list.isEmpty()) { throw new Error(); }
List<Integer> toRemove = new ArrayList<>();
for (int si : list) {
if (si % 2 != 0) { toRemove.add(si); }
}
list.removeAll(toRemove);
return list;//return list, not int
}
Check this line:
int a=list.get(0);
You are reading only the first element of the list, which is 1, and not iterating through it.
Use either an iterator (for each, for example) or a regular for loop (using the item count from list).
As other people have indicated, the problem is that you're returning this:
int a = list.get(0);
Thus, you'll always get the first item in the list, regardless of what you do to it after you retrieve it.
Getting rid of a completely and just returning list will fix that issue.

Java smallest partition of common elements (in the same order) of two or more lists

I'm looking for a quick and smart way to find up until where two lists are equal. In other words I need to find the smallest partition containing common elements in the same order of two or more lists.
It might sound a bit confusing but here is an example of what I want to achieve:
List 1: A, B, C, L, M Z
List 2: A, B, C, K, F
Output -> List 3: A, B, C
I need to use this in a recursive method which should be called with large inputs and all the solutions I've come up with are a bit too slow.
Thanks for your answers in advance
EDIT:
Please excuse me for being unclear. This is my first question and english is not my first language.
Let me explain the problem in a better way. I need to find the intersection of two or more lists starting from the first element of the lists. Please note that elements must be in the same order so it's not exactly an intersection but more like a partition.
the "recursive" thing was just to say that I need to include this in a recursive method which will run many times so I would like the solution to be as fast as possibile as to not lose a lot of time.
Working on an answer that appears to have been deleted I came up with my own solution:
List<String> list1 = new ArrayList<>(Arrays.asList("ciao", "come"));
List<String> list2 = new ArrayList<>(Arrays.asList("ciao", "come", "va"));
List<String> list3 = new ArrayList<>(Arrays.asList("ciao", "come", "va", "?", "tutto", "ok"));
List<List<String>> allLists = new ArrayList<>();
allLists.addAll(Arrays.asList(list1, list2, list3));
int min = Integer.MAX_VALUE;
int listIndex = 0;
for(List<String> list : allLists){
if(min > list.size()){
min = list.size();
listIndex = allLists.indexOf(list);
}
}
int index = 0;
boolean same = true;
while(index<min && same == true) {
String element = allLists.get(listIndex).get(index);
for(List<String> list : allLists){
if(!list.get(index).equals(element)){
same = false;
break;
}
element = allLists.get(listIndex).get(index);
}
if(same == true) ++index;
}
System.out.println("OUTPUT:" + allLists.get(listIndex).subList(0, index));
----> Output: ciao, come
EDIT2:
And also garnful's solution works like a charm and I find it way clearer than mine. Thanks everybody
This should do the work, and hopefully be quite okay regarding the performance:
public List<String> getEqualsPart(List<String>[] listsToCheck) {
if (listsToCheck.length == 0) {
return Collections.emptyList();
}
int minLength = getShortesListLength(listsToCheck);
if (minLength == 0) {
return Collections.emptyList();
}
return getEqualPartsForIndex(listsToCheck, 0, minLength, new ArrayList<String>());
}
private int getShortesListLength(List<String>[] listsToCheck) {
int min = Integer.MAX_VALUE;
for (List<String> currentList : listsToCheck) {
min = Math.min(min, currentList.size());
}
return min;
}
private List<String> getEqualPartsForIndex(List<String>[] listsToCheck, int index, int minLength,
List<String> result) {
if (index == minLength) {
return result;
}
Set<String> setForIndex = new HashSet<>();
Arrays.stream(listsToCheck).forEach(list -> setForIndex.add(list.get(index)));
if (setForIndex.size() > 1) {
return result;
} else {
result.add(setForIndex.iterator().next());
return getEqualPartsForIndex(listsToCheck, index + 1, minLength, result);
}
}`
Try:
public List<E> equalUntil(List<E> l1, List<E> l2) {
return equalUntilRec(l1.iterator(), l2.iterator(), new ArrayList<E>());
}
private int equalUntilRec(Iterator<E> it1, Iterator<E> it2, List<E> acc) {
if(!it1.hasNext() || !it2.hasNext()) {
return acc;
} else {
E e1 = it1.next();
E e2 = it2.next();
if(!e1.equals(e2)) {
return acc;
}
acc.add(e1);
return equalUntilRec(it1, it2, acc);
}
}

Is it possible to find out if a value exists twice in an arraylist?

I have an integer arraylist..
ArrayList <Integer> portList = new ArrayList();
I need to check if a specific integer has already been entered twice. Is this possible in Java?
You could use something like this to see how many times a specific value is there:
System.out.println(Collections.frequency(portList, 1));
// There can be whatever Integer, and I use 1, so you can understand
And to check if a specific value is there more than once you could use something like this:
if ( (Collections.frequency(portList, x)) > 1 ){
System.out.println(x + " is in portList more than once ");
}
My solution
public static boolean moreThanOnce(ArrayList<Integer> list, int searched)
{
int numCount = 0;
for (int thisNum : list) {
if (thisNum == searched)
numCount++;
}
return numCount > 1;
}
If you are looking to do this in one method, then no. However, you could do it in two steps if you need to simply find out if it exists at least more than once in the List. You could do
int first = list.indexOf(object)
int second = list.lastIndexOf(object)
// Don't forget to also check to see if either are -1, the value does not exist at all.
if (first == second) {
// No Duplicates of object appear in the list
} else {
// Duplicate exists
}
This will tell you if you have at least two same values in your ArrayList:
int first = portList.indexOf(someIntValue);
int last = portList.lastIndexOf(someIntValue);
if (first != -1 && first != last) {
// someIntValue exists more than once in the list (not sure how many times though)
}
If you really want to know how many duplicates of a given value you have, you need to iterate through the entire array. Something like this:
/**
* Will return a list of all indexes where the given value
* exists in the given array. The list will be empty if the
* given value does not exist at all.
*
* #param List<E> list
* #param E value
* #return List<Integer> a list of indexes in the list
*/
public <E> List<Integer> collectFrequency(List<E> list, E value) {
ArrayList<Integer> freqIndex = new ArrayList<Integer>();
E item;
for (int i=0, len=list.size(); i<len; i++) {
item = list.get(i);
if ((item == value) || (null != item && item.equals(value))) {
freqIndex.add(i);
}
}
return freqIndex;
}
if (!collectFrequency(portList, someIntValue).size() > 1) {
// Duplicate value
}
Or using the already availble method:
if (Collections.frequency(portList, someIntValue) > 1) {
// Duplicate value
}
Set portSet = new HashSet<Integer>();
portSet.addAll(portList);
boolean listContainsDuplicates = portSet.size() != portList.size();
I used the following solution to find out whether an ArrayList contains a number more than once. This solution comes very close to the one listed by user3690146, but it does not use a helper variable at all. After running it, you get "The number is listed more than once" as a return message.
public class Application {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(8);
list.add(1);
list.add(8);
int number = 8;
if (NumberMoreThenOnceInArray(list, number)) {
System.out.println("The number is listed more than once");
} else {
System.out.println("The number is not listed more than once");
}
}
public static boolean NumberMoreThenOnceInArray(ArrayList<Integer> list, int whichNumber) {
int numberCounter = 0;
for (int number : list) {
if (number == whichNumber) {
numberCounter++;
}
}
if (numberCounter > 1) {
return true;
}
return false;
}
}
Here is my solution (in Kotlin):
// getItemsMoreThan(list, 2) -> [4.45, 333.45, 1.1, 4.45, 333.45, 2.05, 4.45, 333.45, 2.05, 4.45] -> {4.45=4, 333.45=3}
// getItemsMoreThan(list, 1)-> [4.45, 333.45, 1.1, 4.45, 333.45, 2.05, 4.45, 333.45, 2.05, 4.45] -> {4.45=4, 333.45=3, 2.05=2}
fun getItemsMoreThan(list: List<Any>, moreThan: Int): Map<Any, Int> {
val mapNumbersByElement: Map<Any, Int> = getHowOftenItemsInList(list)
val findItem = mapNumbersByElement.filter { it.value > moreThan }
return findItem
}
// Return(map) how often an items is list.
// E.g.: [16.44, 200.00, 200.00, 33.33, 200.00, 0.00] -> {16.44=1, 200.00=3, 33.33=1, 0.00=1}
fun getHowOftenItemsInList(list: List<Any>): Map<Any, Int> {
val mapNumbersByItem = list.groupingBy { it }.eachCount()
return mapNumbersByItem
}
By looking at the question, we need to find out whether a value exists twice in an ArrayList. So I believe that we can reduce the overhead of "going through the entire list just to check whether the value only exists twice" by doing the simple check below.
public boolean moreThanOneMatch(int number, ArrayList<Integer> list) {
int count = 0;
for (int num : list) {
if (num == number) {
count ++ ;
if (count == 2) {
return true;
}
}
}
return false;
}

Categories