Number of subset - java

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.

Related

How to fix my code to write a variant of the solution of the SubSet Sum problem?

Consider the Subset Sum (SUSU) problem, I need to write a variant of the solution shown in class which will also print which weights are aggregated to reach a given sum. For example, if:
sum=12;
int[] weights={1,7,9,3};
the output would be: 0011 That is, for each value in weights, we write "1" if it was added or "0" otherwise.
With the help of a friend, I wrote the following code:
public static void main(String[] args) {
int[] arr={9,1,7,3};
System.out.println(Arrays.toString(SubsetSum(arr,12)));
}
public static int[] SubsetSum(int[] arr, int sum){
int[] output= new int[arr.length];
return SubsetSum(arr,sum, 0, output);
}
public static int[] SubsetSum(int[] arr, int sum, int index, int[]weights){
int[] output= new int[arr.length];
if(sum==0)
return weights;
if(sum<0 | index>=arr.length)
return output;
weights[index]=0;
int[] arr1= SubsetSum(arr,sum,index+1, weights);
weights[index]=1;
int[]arr2=SubsetSum(arr,sum-arr[index],index+1,weights);
boolean isZero=true;
for(int i=0; i<arr1.length & isZero; i=i+1)
if(arr1[i]!=0)
isZero=true;
if(isZero)
return arr2;
else
return arr1;
}
I expect the output of SubsetSum(arr,12) to be [1, 0, 0, 1] but the actual output is [0, 0, 0, 0].
I understand why it return this output from my code, but I don't know how to fix it.
I've changed method of returning result. Now used items are encoded in bits of used parameter.
Ideone.
Main prints indexes of items (or nothing in case of fail) - 1,2,3 for may example, i.e. 1 + 7 + 13
I'm not familiar with Java, so represent result for better viewing (perhaps something like inttobinary)
public static void main(String[] args) {
int[] arr={9,1,7,13,3};
int i = 0;
int res = SubsetSum(arr, 21, 0, 0);
while (res > 0) {
if ((res & 1) > 0)
System.out.println(i);
i++;
res >>= 1;
}
}
public static int SubsetSum(int[] arr, int sum, int index, int used){
if(sum==0)
return used;
if(sum<0 | index>=arr.length)
return 0;
int a = SubsetSum(arr,sum,index+1, used);
int b = SubsetSum(arr,sum-arr[index],index+1, used | (1 << index));
if (a > 0)
return a;
else
return b;
}
}
P.S. Flaws in your code:
isZero is never changed.
If you correct logic to return non-zero array, it will be filled with all 1's - perhaps because weights[index]=1; changes the same array instance through common reference (don't know Java terminology). In my code at every recursion level there is own used instance, and modigying its bits does not influence on values in other branches.

Recursive method for a specific sequence

I am trying to get the value of a sequence at a specific position (where the sequence starts at 0). The formula for this sequence is f(n) = (2^n) - 1 where f(0) = 0.
The sequence goes f(0) = 0, f(1) = 1, f(2) = 3, f(3) = 7, f(4) = 15, etc ...
I wrote this recursive function to find the position. However, my numbers are a bit off. Why are my numbers off?
For this result, if I put in the number f(4), I get the value of what is in f(5) -- 31.
public static int getNumber(int num) {
if(num == 0) {
return 1;
} else {
return (int)Math.pow(2,num) + getNumber(num-1);
}
}
I understand that the problem lays within my base case. How can I fix it?
You said f(0) = 0, but your code checks if num == 0, and if it is, returns 1. You just need to return 0 if num == 0.
Although I don't think your recursion will work correctly the way you want it to, either. 2^n - 1 can be expressed as the sum of all powers of 2 less than n, and yours sums up the powers of two less than or equal to n. So you should probably be taking Math.pow(2, num - 1) while you're at it.
Your instructions say f(0) is 0. Also, your function isn't recsursive. I think you wanted 2n - 1 like
public static int getNumber(int num) {
if (num == 0) {
return 0;
}
return (int) (Math.pow(2, num) - 1);
}
I tested it like,
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.printf("f(%d) = %d%n", i, getNumber(i));
}
}
And got your expected results. Of course, you could use a bitshift instead of Math.pow (since it's 2). Like,
public static int getNumber(int num) {
if (num == 0) {
return 0;
}
return (1 << num) - 1;
}
And get the same results.

Retrieving specific combinations

Given an Integer set, {x | 1 <= x <= n}. Consider a combination, something like 50C6 (select 6 from 50). Calculating the number of combinations and iterating over them (in sorted order) is easy.
For example, this does the trick:
public static void combo(int[] combo, int index, int f, int t) {
if (index >= combo.length) {
// display combination
// ...
return;
}
for (int i = f; i <= t - (combo.length - index) + 1; i++) {
combo[index] = i;
combo(combo, index + 1, i + 1, t);
}
}
For the above, calling combo(new int[]{0, 0, 0, 0}, 0, 1, 9) will list all the 9C4 combinations in sorted order, all 126 of them.
What I would like is the following. Given k, I'd like the algorithm to give the combination.
// Select r from c and return combination k.
public static int[] combo(int c, int r, int k) {
}
For example, combo(3,2,1) should return {1,2} and combo(3,2,3) should return {2,3} (assuming the first combination is 1 and not 0 - but that's trivial).
Doing this in O(nCr) is easy and takes little memory... Doing it in O(1) is also easy, but is requires lots of memory for larger combinations and requires pre-calculation. I don't know whether it's possible to do this in better time than O(nCr) without using a lookup table. Any confirmation/guidance would be appreciated.
Okay, I've worked it out and I am quite happy with the final result. The basic idea is as follows:
Let's say we want the k'th entry of nCr. Then, the number of combinations where we start with a 1 is (n-1)C(r-1) and a 2 is (n-2)C(r-2), etc. So, all you have to do is find out which digit needs to go at the first spot and then repeat the process for every one of the r spots.
For example, let's say we want the 30'th entry of 9C3. For 1, we have 8C2 = 28. That's not enough. For 2, 7C2 = 21. So, the first digit must be a 2 and the first entry that started with a 2 was entry 29. So now you simply repeat this process for the second and third entry.
The non-recursive solution is as follows:
public static int[] getCombo(int n, int r, int k) {
int[] result = new int[r];
int cur = 1;
int sum =0;
while (r > 0) {
int tot = c(n - cur, r - 1);
if (sum + tot < k) {
sum += tot;
cur++;
} else {
result[result.length - r] = cur++;
r--;
}
}
return result;
}
The function c() above, simply calculates "n select r".
I particularly like this as it is O(r).
So you can find the value of nCp by the equation n!/(p!*(n-p)!). So say you're solving 4C3 and you're looking for the kth combo. If the first value is a 1 then that means that you have 3C2 left which calculates to 3. So if k < 3 the first value is a 1. If not you go to 3C2 + 3C1 for the second value. And you recuse down the line. No sure if it's actually faster (the calculation of nCp) but it's an interesting way to think about the problem.

Java Recursion compilation error

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);
}
:-)

Java Algorithm Question

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);
}

Categories

Resources