Related
class Solution {
int f(int[] a, int s, int n) {
if (n == 0)
return s;
return f(a, s + 1, n - 1) + f(a, s, n - 1);
}
}
class Test {
public static void main(String[] args) {
int[] a = { 1, 1, 2, 3 };
System.out.println(new Solution().f(a, 0, a.length));
}
}
I have written a code to print the number of subset, at every index I got two choices whether to include the a[i] in the subset or not for that I add 1 to s whenever the element is to be included, but this approach gives wrong answer. Why it is wrong?
Math.pow(2, a.length)
would be the obvious solution for that. but if you really want to find it that way it should 'return 1' instead of 'return s' since each time it arrives at zero, it means no element is left, thus empty list, thus 1.
I am told to write a recursive function that takes a start index, array of integers,and a target sum, your goal is to find whether a subset of of the array of integers adds up to the target sum.
The example I am given is groupSum(0, {2, 4, 8}, 10) should return true because 2 and 8 add up to the target, 10. All I've been able to do so far are the base cases.
public boolean groupSum(int start, int[] nums, int target) {
if (nums.length == 0)
{
return false;
}
else if (start == nums.length - 1)
{
return nums[start] == target;
}
else
{
?????
}
}
I have no idea where I should go with the actual recursive call. Since I can't pass a collective sum between calls, I don't see how I can add a number in each recursive call until I reach the target. Also, like shown in the example, I have no idea how I could have my code realize when a number won't work and just skip it, like the example did with 4. I'm thinking along the lines of that I should subtract numbers one at a time from int target and then recursively call the method with a new starting point and the new value for target, but I have no idea how I could use that to see if there is a valid subset.
I would appreciate any help that can help me understand how to do this problem so that I can finish it. Thanks!
As you point out you can change the target rather than passing a collective sum. Once the target is zero you know that you've got a solution (by selecting no members of the remaining items).
So, in psueduo code:
hasMembersThatSumTo(list, total):
if total == 0
return true
else if total < 0 or list is empty
return false
else
int first = list.pop
return hasMembersThatSumTo(list, total - first)
or hasMembersThatSumTo(list, total)
The two cases in the 'or' statement are looking for this situation in which the current element is either in or not in the sum.
Here is a working version. See comments in the code for explanation.
public static boolean recursiveSumCheck(int target, int[] set) {
//base case 1: if the set is only one element, check if element = target
if (set.length == 1) {
return (set[0] == target);
}
//base case 2: if the last item equals the target return true
int lastItem = set[set.length - 1];
if (lastItem == target) {
return true;
}
//make a new set by removing the last item
int[] newSet = new int[set.length - 1];
for (int newSetIndex = 0; newSetIndex < newSet.length; newSetIndex++) {
newSet[newSetIndex] = set[newSetIndex];
}
//recursive case: return true if the subset adds up to the target
// OR if the subset adds up to (target - removed number)
return (recursiveSumCheck(target, newSet) || recursiveSumCheck(target - lastItem, newSet));
}
dynamic programming. Maybe this will help you.
This should work according to the given conditions.
Initially the value of start = 0
boolean subsetSum(int start, int[] nums, int target) {
// target is the sum you want to find in the nums array
if (target == 0) return true;
if (start > nums.length-1 || nums.length == 0)
return false;
if (nums[start] > target)
return subsetSum(start+1, nums, target);
return subsetSum(start+1, nums, target) || subsetSum(start+1, nums, target - nums[start]);
}
I am writing a function according to the following guidelines:
Given an array of ints, is it possible to choose a group of some of the ints, beginning at the start index, such that the group sums to the given target? However, with the additional constraint that all 6's must be chosen. (No loops needed.)
groupSum6(0, {5, 6, 2}, 8) → true
groupSum6(0, {5, 6, 2}, 9) → false
groupSum6(0, {5, 6, 2}, 7) → false
This is the solution:
public boolean groupSum6(int start, int[] nums, int target) {
if (start == nums.length) {
if (target == 0) {
return true;
}
return false;
}
if (nums[start] == 6) {
return groupSum6(start + 1, nums, target - nums[start]);
}
if (groupSum6(start + 1, nums, target - nums[start])) {
return true;
}
return groupSum6(start + 1, nums, target);
}
I am a little confused about why this works. I understand how it adds 6s, but where are the other numbers tested to see if they will add up to the target after the 6s have been added? Where are other non-6 numbers added?
The reason this works is that the recursive call always checks to see if the number at the current index is a 6 and subtracts that from the target. So the order of evaluation is:
1)
if (start == nums.length) {
if (target == 0) {
return true;
}
return false;
}
Check to see if the passed index is the length of the array (so this would mean the index is BEYOND the bounds of the array - the last index of the array would be nums[nums.length - 1] ). If yes, AND if the target is 0, return true. Otherwise return false, because there are no more values to check
2)
if (nums[start] == 6) {
return groupSum6(start + 1, nums, target - nums[start]);
}
Check if the number at the index is 6. If it is, subtract 6 from the target, add one to the index, and check the remaining values.
3) Otherwise...
if (groupSum6(start + 1, nums, target - nums[start])) {
return true;
}
Evaluate if the rest of the array works to add up to the target. If it does return true. The key is to notice that this step will always happen AFTER we check if the value is a 6. Essentially here you are looking for a solution that COUNTS the number in the start index. If a solution is found we can end. If no solution is found using the number at num[start], then we go on to:
4)
return groupSum6(start + 1, nums, target);
Checking for a solution that exists when we DON'T use the number at num[start].
The key is that each time the recursive call is made the check for a 6 is done first ( assuming you aren't beyond the bounds of the array).
The idea is to test all the possible subarray options, something like "what happen if i get next element?" and... "what happen if i don't?".
So, for any element in the array your are making two recursive calls (two options, take it or not) and... if one of them is OK the solution is reached (so return true).
In the next recursive call you pick the number, so you call with the next index element (start+1) and substract the picked number from the target (imagine your target is 8 and the current element is 2... the recursive call is to check the next numbers with target 8-2= 6).
if (groupSum6(start + 1, nums, target - nums[start])) {
return true;
}
The next recursive call is the same but you don't pick the current number so... target will be the same (in the previous example you will check the next number with target 8);
return groupSum6(start + 1, nums, target);
And... here it comes the 6 restriction... if you find a 6 then you have no more options than to pick the number so... you put that condition first (and in this scenario there is only one call because you have no options):
if (nums[start] == 6) {
return groupSum6(start + 1, nums, target - nums[start]);
}
Just do this check if the number is 6 and then decide to skip it
public boolean groupSum6(int start, int[] nums, int target) {
//exit condition and if target becomes 0
if(start >= nums.length) return (target ==0);
// subtracting the number at start from target and make a recursive //call to groupSum6
if(groupSum6(start+1 , nums , target - nums[start])) return true;
//check if the number at start is 6 or not then decide to skip it
if(nums[start] != 6 && groupSum6(start+1 , nums , target)) return true;
//if target does not becomes 0
return false;
}
I am a fresh student in computer science and currently we study Java recursion. Unfortunately, the academy only explains the following regarding this topic:
What recursion means.
There are 2 types of cases when using a recursive algorithm: base cases and recursive cases and their purpose.
An example of factorial and Fibonacci implementation using recursion.
Now I got the following exercise:
Two integer numbers will be called "strangers" if their greatest common divisor (aka GTC) is ONLY 1". For example, the numbers 8 and 9 are "strangers" because their GTC is 1. However, 8 and 9 are not "strangers" because their GTC is 2.
Please implement a recursive method which receives an array of integers, and returns "true" if every pair numbers in this array are strangers, and "false" otherwise.
Method signature must be as follows:
public boolean checkGCD(int[] values)
For example:
{3, 5, 7, 11} -> method will returns true.
{4, 7, 8, 9} -> method will returns false because 4 and 8 are not strangers.
For assistance, you can use the following method for finding GTC (Euclidean algorithm):
private static int gcd(int n, int m){
if (m==0)
return n;
return gcd(m,n % m);
}
In addition, the method checkGCD(int[] values) should be overloaded...
Loops cannot be used!
The above can be done very easily with a nested loop, but I must use recursion!
I understand that I need to use an overloaded method which gets the array, lo index and hi index.
So this is what I came up in mind:
######
Base case: if there is at least one pair of numbers in the array which are not strangers, method returns false (no need to continue the comparison...).
######
Comparison will be done in the following way: lo index points to the 1st cell -> hi index points to the 2nd cell -> comparing -> hi index is incremented by 1 until it reaches the last cell of the array.
Then, lo index is incremented by 1, and then repeating the above.
So bottom line, I should compare the first cell to all consecutive cells, compare the 2nd to all consecutive cells, the 3rd etc...
########
If all pairs of numbers are strangers, I need something else to stop recursion. Therefore, if all pairs are strangers, it means that lo index and hi index will eventually point to the last cell (cause both lo and hi index has incremented gradually, and they reach the last array cell after all comparisons turned out to be OK i.e strangers).
The following is the overloaded function:
private static boolean checkGCD(int[] values, int lo, int hi)
{
if ( (gcd(values[lo], values[hi]) )!= 1 )
return false;
else if (lo < values.length-1 && hi < values.length-1)
return checkGCD(values, lo, hi+1);
else if (lo < values.length-2 && hi == values.length-1)
return checkGCD (values, lo+1, lo+2);
if (lo == values.length-1 && hi == values.length-1)
return true;
} -> Compiler says "missing return statement"**
The following is the method the exercise requires to have, and it basically just calls the overloaded method which does everything recursively.
public static boolean checkGCD(int[] values)
{
return checkGCD(values, 0, 1);
}
When I try to compile, I get "missing return statement" which points to the close bracket in the overloaded function
But I do use "return" in the overloaded function.
Please clarify how to fix. I am sure after compilation error, the above overloaded function is still not OK.
You get the compiler error because, if every if fails, the method does not return anything. The solution is add the appropriate return statement when the final if fails.
Not to give the answer away, but here's a strong hint: the base case is an array with two elements. All larger arrays are recursive cases.
There's a general pattern for going through a list with a recursion (pseudocode):
Result f(List f) {
if(f is an empty list) {
return Result for an empty list;
} else {
return (Result for head of list) merged with f(tail of list)
}
}
Since you're using arrays, rather than a type with convenient head() and tail() methods, you could pass in an index to say how much of the array you want to process. When index == array.length you are processing an "empty list".
boolean allMembersPositive(int[] array, int index) {
if(index == array.length) {
return true;
} else {
return (array[index] >=0) && (allMembersPositive(index + 1));
}
}
It's a small step to adapt this to consume two array items per recursive call.
I can guarantee you that when you understand recursion clearly you are going to level up your programming skills.
I recommend reading these URLs:
http://howtoprogramwithjava.com/java-recursion/
http://danzig.jct.ac.il/java_class/recursion.html
Now, lets move back to your questions. I think that is one possible way to implement it:
public class Test {
public static void main(String[] arguments) {
int[] strangers = { 3, 5, 7, 11 };
int[] acquaintances = { 4, 7, 8, 9};
boolean verifyStrangers = checkGCD(strangers);
boolean verifyAcquaintances = checkGCD(acquaintances);
System.out.println(verifyStrangers);
System.out.println(verifyAcquaintances);
}
public static boolean checkGCD(int[] values) {
return checkGCD(values, 0, 1);
}
/*
* I'm really not sure why your professor wants this method signature: "checkGCD(int[] values, int i, int j)"
* I'm coding what I understood from the problem.
*/
private static boolean checkGCD(int[] values, int i, int j) {
boolean result = true;
if (gcd(values[i], values[j]) != 1){
result = false;
}
j++;
if (j < values.length ) {
result = result && checkGCD(values, i, j);
}
return result;
}
private static int gcd(int n, int m) {
if (m == 0)
return n;
return gcd(m, n % m);
}
}
I managed to solve the exercise.
public static int gcd(int n, int m)
{
if (m==0)
return n;
return gcd(m,n % m);
}
private static boolean checkGCD(int[] values, int lo, int hi)
{
// System.out.println("lo is " + lo + " hi is " + hi);
// System.out.println("");
// System.out.println("[lo] is " + values [lo] + " [hi] is " + values[hi]);
// System.out.println("");
if ( (gcd(values[lo], values[hi]) )!= 1 )
return false;
if (lo < values.length-1 && hi < values.length-1)
return checkGCD(values, lo, hi+1);
if (lo < values.length-2 && hi == values.length-1)
return checkGCD(values, lo+1, lo+2);
if (lo == values.length-2 && hi == values.length-1)
return true;
return true;
}
public static boolean checkGCD(int[] values)
{
return checkGCD(values, 0, 1);
}
:-)
Problem Statement :: In Java ,Given an array of ints, is it possible to choose a group of some of the ints, such that the group sums to the given target, with this additional constraint: if there are numbers in the array that are adjacent and the identical value, they must either all be chosen, or none of them chosen. For example, with the array {1, 2, 2, 2, 5, 2}, either all three 2's in the middle must be chosen or not, all as a group. (one loop can be used to find the extent of the identical values).
groupSumClump(0, {2, 4, 8}, 10) → true
groupSumClump(0, {1, 2, 4, 8, 1}, 14) → true
groupSumClump(0, {2, 4, 4, 8}, 14) → false --> Failing Test Case
groupSumClump(0, {8, 2, 2, 1}, 9) → true --> Failing Test Case
groupSumClump(0, {8, 2, 2, 1}, 11) → false --> NegativeArraySizeException
I have done some initial Analysis and the partial code is as below.
public boolean groupSumClump(int start, int[] nums, int target) {
start = 0;
boolean flag = false;
// get the highest int from the list of array we have
int highestInteger = getTheBiggest(nums);
if (highestInteger > target) {
flag = false;
} else {
int variable = 0;
for (int i = 0; i < nums.length; i++) {
variable += nums[i];
}
if (variable == target) {
flag = true;
} else {
if (variable < target) {
flag = false;
} else {
// here goes ur grouping logic here
flag = summate(highestInteger, target, nums);
}
}
}
return flag;
}
private boolean summate(int highestInteger, int target, int[] nums) {
boolean val = false;
if (highestInteger == target) {
val = true;
} else {
int[] temp = new int[nums.length - 1];
int var = 0;
if ((target - highestInteger) > 0) {
for (int j = 0; j < nums.length-1; j++) {
if (nums[j] != highestInteger) {
temp[var] = nums[j];
if (temp[var] == (target - highestInteger)) {
val = true;
return val;
}
var++;
}
}
val = summate(getTheBiggest(temp), target - highestInteger,
temp);
}
}
return val;
}
private int getTheBiggest(int[] nums) {
int biggestInteger = 0;
for (int i = 0; i < nums.length; i++) {
if (biggestInteger < nums[i]) {
biggestInteger = nums[i];
}
}
return biggestInteger;
}
Please Note: I dont know how to handle the logic for below problem statement :
There is an Additional Constraint to the problem such that if there are numbers in the array that are adjacent and the identical value, they must either all be chosen, or none of them chosen. For example, with the array {1, 2, 2, 2, 5, 2}, either all three 2's in the middle must be chosen or not, all as a group. (one loop can be used to find the extent of the identical values).
how should i handle this part of logic in above problem.
I have been struggling to get this right with no idea.
Suggestions provided will be appreciated.
Culd you let me know what is the problem with the code/how to handle the additional constraint in this problem, :-((
Additional constraint says either u select as a group and not select as a group.so i dont know how to proceed.if u can PLEASE help me.it will be appreciated.
EDIT FOR USER->MISSINGNO: I have added the below code construct to above main code and it prints me wrong values.where have i gone wrong.
groupSumClump(0, {2, 4, 4, 8}, 14) → false is failing again
2
8
4
The flag is -->true which is wrong.
for(int number=0;number<nums.length-1;number++){
if(nums[number]==nums[number+1]){
nums[number]=nums[number]+nums[number+1];
}
}
I would convert the array to a simpler array that can be solved with your previous method, by clumping the adjacent values:
{1, 2, 2, 2, 5, 2} --> {1, 6, 5, 2}
You might want to keep some extra bookkeeping info though to be able to find the original solution from a solution to the altered problem.
This problem is similar to finding group of integers in an array which sum up to a given target.
Hint for this problem is:
The base case is when start>=nums.length. In that case, return true if target==0. Otherwise, consider the element at nums[start]. The key idea is that there are only 2 possibilities -- nums[start] is chosen or it is not. Make one recursive call to see if a solution is possible if nums[start] is chosen (subtract nums[start] from target in that call). Make another recursive call to see if a solution is possible if nums[start] is not chosen. Return true if either of the two recursive calls returns true.
You can use the same hint but with a loop in it to find sum of repeated numbers in array. Make a call to see if a solution is possible if the sum is chosen and make another call if the sum is not chosen.Return true if either of the two recursive calls returns true.
I think this would help.
public boolean groupSumClump(int start, int[] nums, int target)
{
if(start >= nums.length) return target == 0;
int count = 1;
while(start+count < nums.length && nums[start] == nums[start+count])
count++;
if(groupSumClump(start+count, nums, target-count*nums[start])) return true;
if(groupSumClump(start+count, nums, target)) return true;
return false;
}
You Have taken quite a lengthy approach to solving this question. Try thinking more recursively.
For the Base Case, we'll check if the start is greater than or equal to the length of the provided array(nums). If it is true, we'll check if we've reached the target sum, i.e. target is equal to 0 or not. If it is, then we'll return true as we have an answer, else return false because we have traversed the whole array, and still not reached our target.
Base Case -
if(start>=nums.length)
return target==0;`
Now, we'll take a counter variable int c=1;. We'll use it to count the number of repeating characters present(if any). How we'll do it is, we will use a while loop and iterate till nums[start] to nums[start+c] and keep on increasing the counter by 1. When this loop will end, if the value of c is 1, then we didn't find any repeating characters. Else, we have found c repeating characters of nums[start]. Make Sure you don't go out of bounds in this while loop.
int c=1;
while(start+c<nums.length&&nums[start]==nums[start+c])
c++;
Now, you know if you have repeating characters or not. You either have to include all of them or none of them. We already have c, so now we just have to call the function in which it includes c*nums[start] or it doesn't include c*nums[start]
Now, if we have repetitions, the function will skip or take all of the same values. But if we don't have repetitions, just because the value of c is 1, the function call will work in this case too. Try to dry run the code to get a better idea.
In the end, if all the function calls return false, then we know that we don't have an answer, so we too will return false.
public boolean groupSumClump(int start, int[] nums, int target) {
if(start>=nums.length)
return target==0;
int c=1;
while(start+c<nums.length&&nums[start]==nums[start+c])
c++;
if(groupSumClump(start+c,nums,target-
c*nums[start])||groupSumClump(start+c,nums,target))
return true;
return false;
}
Once you've done missingno's preprocessing step (in linear time) what you have is essentially the subset sum problem. It's a rather hard problem, but approximate algorithms exist- might as well turn out to be practical depending on how long your sequence is.
the problem statement is ambigious and not clear:
with this additional constraint: if there are numbers in the array
that are adjacent and the identical value, they must either all be
chosen, or none of them chosen. For example, with the array {1, 2, 2,
2, 5, 2}, either all three 2's in the middle must be chosen or not,
all as a group
how about choosing single digits if the 'streaks' did not work out?
same example: {1,2,2,2,5,2}
in one recursive call we choose the streak of 2 2 2 (from answer above)
*if(groupSumClump(start+count, nums, target-count*nums[start])) return true*
in the next rec. call why can't we subtract the first single digit at nums[start]:
if(groupSumClump(start+count, nums, target)) return true;
can i do this:
if(groupSumClump(start+1, nums, target - nums[start])) return true;
DOES IT MEAN WE CAN NEVER CHOOSE SINGLE DIGITS?
Your public method parameter list for the method groupSumClump should not expose the start parameter, especially if you have an internal variable that overrides it.
Have a look at this implementation. The time complexity for the solve method is O(2^N), since in the worst case you are obliged to check all possible subsets of nums. Well unless someone proves that NP = P.
I Hope it helps.
import java.util.*;
public class SubsetSumSolver {
public boolean solve(int[] nums, int target) {
return solve(0, 0, target, mergeSameNumbers(nums));
}
private boolean solve(int start, int tempSum, int sum, ArrayList<Integer> nums) {
if (start == nums.size())
return sum == tempSum;
return solve(start + 1, tempSum + nums.get(start),sum, nums) || solve(start + 1, tempSum, sum, nums);
}
private ArrayList<Integer> mergeSameNumbers(int[] nums) {
if (nums.length == 0)
return toArrayList(nums);
LinkedList<Integer> merged = new LinkedList<>();
int tempSum = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i - 1] == nums[i])
tempSum += nums[i];
else {
merged.add(tempSum);
tempSum = nums[i];
}
}
merged.add(tempSum);
return new ArrayList(merged);
}
private ArrayList<Integer> toArrayList(int[] nums) {
ArrayList<Integer> result = new ArrayList();
for (int index = 0; index < nums.length; index++)
result.add(nums[index]);
return result;
}
}
My solution with a HasMap.
public boolean groupSumClump(int start, int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Arrays.sort(nums);
for (int i : nums) {
if (!map.containsKey(i)) {
map.put(i, 1);
}
else {
map.put(i, map.get(i) + 1);
}
}
return groupSumClumpHelper(start, nums, target, map);
}
private boolean groupSumClumpHelper(int start, int[] nums, int target, Map map) {
if (start >= nums.length) {
return target == 0;
}
if (!map.get(nums[start]).equals(1)) {
return groupSumClumpHelper(start + Integer.parseInt(map.get(nums[start]).toString()), nums, target - Integer.parseInt(map.get(nums[start]).toString()) * nums[start], map) ||
groupSumClumpHelper(start + Integer.parseInt(map.get(nums[start]).toString()), nums, target, map);
}
return groupSumClumpHelper(start + 1, nums, target - nums[start], map) || groupSumClumpHelper(start + 1, nums, target, map);
}