Given a set of non-negative integers, and a value sum, determine if there is a subset of the given set with sum equal to given sum.
For example:
set = {1,2,5,7}
sum = 8
=> true
I actually solved the problem with this code:
public boolean isSubsetSum(int[] set, int sum) {
Arrays.sort(set);
boolean[][] memo = new boolean[set.length+1][sum+1];
for (int i = 0; i < memo.length; i++) {
memo[i][0] = true;
}
for (int i = 1; i < memo.length; i++) {
for (int j = 1; j < memo[i].length; j++) {
if (set[i-1] > j) {
memo[i][j] = memo[i-1][j];
} else {
memo[i][j] = memo[i-1][j] || memo[i-1][j-set[i-1]];
}
}
}
return memo[memo.length-1][memo[memo.length-1].length-1];
}
However, now I want to reconstruct all the possible combinations that form the given sum.
Is it possible to do that from my memoization matrix or do I have to do it differently?
Make a new DP table called take[i][j] which is boolean. It is true if you take the i-th element for subset sum j. You fill it concurrently with your normal memo table:
for (int i = 1; i < memo.length; i++) {
for (int j = 1; j < memo[i].length; j++) {
if (memo[i-1][j]){
//no need to take ith elements, first i-1 have sum j
take[i][j] = false;
memo[i][j] = true;
}
else if (j-set[i-1] >= 0 && memo[i-1][j-set[i-1]]){
//take ith element, and search for set of size j-set[i-1] in 1..i-1
take[i][j] = true;
memo[i][j] = true;
}
else{
//neither memo[i-1][j] or memo[i-1][j-set[i-1]] valid, so no way to make sum
take[i][j]=false;
memo[i][j]=false;
}
}
}
Finally, to reconstruct a solution, you start with:
int i =set.length
int j = sum
while (i>=0 && j>=0){
if (take[i][j]){
print(set[i])
j = j - set[i]
i=i-1
}
else{
i=i-1
}
}
You can generalize this for all sets of solutions.
Related
I have a nested loop that loops through every element in the list comparing it/sorting it , then I am trying to square the numbers in the list(keep in mind they need to be sorted). The problem is when I run my program, the 'test' array list that I am using does not print the last one squared, but it prints the second to last one squared twice. For example, if my array list is (1,2,3,4,5) my code should print (1,4,9,16,25) but instead it prints (1,4,9,16,16). I can't seem to figure out why.
My code:
public static void sortSquares(List<Integer> tempList) {
int result = 0;
for (int i = 0; i < tempList.size(); i++) {
for (int j = tempList.size() - 1; j > i; j--){
if (tempList.get(i) > tempList.get(j)) {
result = tempList.get(j) * tempList.get(j);
}
else if (tempList.get(j) > tempList.get(i)) {
result = (tempList.get(i) * tempList.get(i));
}
}
System.out.println(result);
}
}
Solution won't work if tempList[i] == tempList[j].Replace else if with else and it will work.
In the last external loop when i = 4, the inner loop becomes:
for (int j = 4; j > 4; j--)
which does nothing, and the outer loop prints result, which contains the previous value (16).
The solution could be to replace the condition for the inner loop to j >= i. You also need to replace the condition of the if, as tempList.get(j) will now be equal to tempList.get(i):
for (int i = 0; i < tempList.size(); i++) {
for (int j = tempList.size() - 1; j >= i; j--){
if (tempList.get(i) > tempList.get(j)) {
result = tempList.get(j) * tempList.get(j);
}
else if (tempList.get(j) >= tempList.get(i)) {
result = (tempList.get(i) * tempList.get(i));
}
}
System.out.println(result);
}
It will work for (1,2,3,4,5).
That being said, the same result could be attained with a simpler code:
Collections.sort(tempList); /* Optional, if you want to sort the result */
List<Integer> result = new ArrayList<>();
for (int i = 0; i < tempList.size(); i++) {
result.add(tempList.get(i) * tempList.get(i));
}
System.out.println(result);
I have a hashmap containing (point, value), I calculate the minimum value in the hashmap. Second, the retreived point I uuse it to extract corresponding values from a matrix.
then I store xmmin, and the points retreived in an arraylist
My objective is to not consider a point if it already exists in the arraylist.
I have tried this but It stucks with the first min.
Here is what I've tried
List<Integer> dataPoints = new ArrayList(); // Storing parsed elements including Xmin
HashMap<Integer, List<Integer>> clusters = new HashMap<>();
ArrayList<Integer> listt = new ArrayList<>();
List<Integer> l = new ArrayList<>(); //list of points for each xmin
while(E.size()!=dataPoints.size()) {
int xMin = getKey(E,MinX(E));
System.out.println("Xmin "+xMin);
if (!existsX(dataPoints, xMin)) {
dataPoints.add(xMin);
//checking id X exists in data points if no return close elements
for (int j = 0; j < S.getRow(xMin).length; j++) {
if (S.getEntry(xMin, j) > beta) {
l.add(j);
dataPoints.add(j);
}
}
}
Here is IfExists function
for (int k = 0; k < dataPoints.size(); k++) {
if (dataPoints.get(k) != xMin) {
return false;
}
}
return true;
}
How can I achieve that
Currently, your existsX-method contains this:
for (int k = 0; k < dataPoints.size(); k++) {
if (dataPoints.get(k) != xMin) {
return false;
}
}
return true;
Which will immediately return false at the first item that isn't the xMin, while you want to accomplish the opposite: return true as soon as xMin is found like this:
for (int k = 0; k < dataPoints.size(); k++) {
if (dataPoints.get(k) == xMin) { // != has been changed to ==
return true; // Return true as soon as we've found it
}
}
return false; // Return false if it wasn't found
Better yet however, would be to rely more on builtins that do the work for you. In this case your:
if(!existsX(dataPoints,xMin))
Can be changed to:
if(!dataPoints.contains(xMin))
So you won't need to make your own existsX-method. Here the JavaDocs for the List#contains builtin.
Your ifExists should be
for (int k = 0; k < dataPoints.size(); k++) {
if (dataPoints.get(k) == xMin) {
return true;
}
}
return false;
My code throws a run-time error, can anyone explain why? My solution envolves adding to an array the differences between j and i, and then find the minimum of the two, only to return it. But for some reason it gives me a timeout error. The question is question is this:
We define the distance between two array values as the number of indices between the two values. Given A find the minimum distance between any pair of equal elements in the array. If no such value exists, print -1 The minimum difference is calculated by the difference between index j and index i
static int minimumDistances(int[] a) {
int[] difference = new int[a.length];
int lowest = 0;
boolean pairFound = false;
for(int i = 0; i < a.length; i++) {
for(int j = i + 1; j < a.length; j++) {
for(int l = 0; l < difference.length; l++) {
if(a[i] == a[j]) {
difference[l] = j - i;
pairFound = true;
} else if(pairFound == false) {
lowest = -1;
}
}
}
}
if(pairFound == true) {
lowest = difference[0];
for(int i = 0; i < difference.length; i++) {
if(difference[i] < lowest) {
lowest = difference[i];
}
}
}
return lowest;
}
Give this a try and check to see if this works:
int[] difference = new int[a.length];
You are looping 3 times, that is 𝓞(n³) too slow. Try a different approach.
Here is my code using streams.
static int minimumDistances(int[] a) {
Map<Integer,List<Integer>> map = IntStream.range(0, a.length).boxed()
.collect(Collectors.groupingBy(i -> a[i]));
return map.entrySet().stream().filter(m -> m.getValue().size() > 1)
.map(m -> m.getValue().stream()
.reduce((acc,val)-> Math.abs(acc - val)).get())
.mapToInt(Integer::valueOf).min().orElse(-1);
}
I am writing a program that, using an array list of given integers (listOfNumbers), will find if any combination of sums of these numbers will add up to another given integer (CompareTo). This program uses recursion. I am stuck on figuring out how to end the recursion loops as soon as the list number(s) is found. Thanks.
int sum = 0;
for(int i = listOfNumbers.size() - 1; i > -1; i--)
{
int backup = listOfNumbers.get(i);
listOfNumbers.remove(i);
for(int k = 0; k < listOfNumbers.size(); k ++)
{
sum += listOfNumbers.get(k);
}
if(sum == compareTo)
{
//IF THIS IS TRUE KILL ALL RECURSION
return listOfNumbers;
}
sum = 0;
answer(listOfNumbers, compareTo); //CREATE NEW RECURSION LOOP
listOfNumbers.add(i, backup);
}
//IF NO COMBINATION OF ARRAY LIST NUMBERS WILL
//ADD TO = COMPARETO, RETURN ORIGINAL LIST
return listOfNumbers;
Try to compare first, and then add or remove numbers in the list. If you remove numbers before the recursive call, in subsequent returns the condition isn't meet.
int sum = 0;
for(int i = listOfNumbers.size() - 1; i > -1; i--)
{
if(sum == compareTo)
{
//IF THIS IS TRUE KILL ALL RECURSION
return listOfNumbers;
}
else
{
int backup = listOfNumbers.get(i);
listOfNumbers.remove(i);
for(int k = 0; k < listOfNumbers.size(); k ++)
{
sum += listOfNumbers.get(k);
}
sum = 0;
answer(listOfNumbers, compareTo); //CREATE NEW RECURSION LOOP
listOfNumbers.add(i, backup);
}
}
//IF NO COMBINATION OF ARRAY LIST NUMBERS WILL
//ADD TO = COMPARETO, RETURN ORIGINAL LIST
return listOfNumbers;
In fact, I would put the obvious case (sum == compareTo) in the very top of everything, and then do the rest of the stuff.
for(int k = 0; k < listOfNumbers.size(); k ++)
{
sum += listOfNumbers.get(k);
}
if(sum == compareTo)
{
//IF THIS IS TRUE KILL ALL RECURSION
return listOfNumbers;
}
// DO THE REST OF OPERATIONS HERE....
There are many symbol games working in this way so this should sound familiar to you.
Facts:
I have two arrays with same length of 4.
(A[4] and B[4])
I fill them with random integers from 1 to 6.
I can NOT sort them in any way (they must stay the same).
Problems:
I need to compare them and after that I need to have 3 values. FIRST one needs to count how many elements are the same and in the same place. I do it like this and it is working:
int first = 0;
int k = 0;
for (int j=1; j<=4; j++)
{
k++;
if (A[k] == B[j])
{
first++;
}
}
SECOND one needs to count how many elements are the same BUT not at the same place. THIRD one needs to count how many elements are not the same at all.
I need a solution to count either SECOND or THIRD number, because after that I can just subtract like 4-(first+second) or 4-(first+second).
Here's the logic you should use: loop over the first array; for each element, check if the corresponding element of the second array is the same - if yes, increment your first counter. If they are not the same, then check whether the second array contains the corresponding element of the first array. If it does, then it's definitely not in the same position (you just checked same positions) - increment your second count. Otherwise, increment your third count. The code can be as following:
int[] A = {...};
int[] B = {...};
List<Integer> lstB = new ArrayList<Integer>(B.length);
for (int index = 0; index < B.length; index++) {
lstB.add(B[index]);
}
int first = 0, second = 0, third = 0;
for(int i=0; i<4; i++) {
if(A[i] == B[i]) {
first++;
}
else if(lstB.contains(A[i]) {
second++;
}
else {
third++;
}
}
SOLUTION
Eventually I made the right algorithm. In general, the solution is to keep track of what fields you used when counting FIRST value. And here is the code:
int first = 0;
int second = 0;
int third = 0;
boolean[] codeUsed = new boolean[4];
boolean[] guessUsed = new boolean[4];
//same value and same place
for (int i = 0; i < 4; i++)
{
if (A[i] == B[i])
{
first++;
codeUsed[i] = guessUsed[i] = true;
}
}
//same value but not right place
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (!codeUsed[i] && !guessUsed[j] && A[i] == B[j])
{
second++;
codeUsed[i] = guessUsed[j] = true;
break;
}
}
}
//not the same value
third = 4 - first - second;