I had a recursion interview question problem in Java,Need your help on this.
Write a **Java function** such that :: Given an array of ints, is it possible to divide the ints into two groups, so that the sum of the two groups is the same, with these constraints: all the values that are multiple of 5 must be in one group, and all the values that are a multiple of 3 (and not a multiple of 5) must be in the other. (No loops needed.)
split53({1,1}) → true
split53({1, 1, 1}) → false
split53({2, 4, 2}) → true
PS:This was a Interview Question for hewlett packard
The question can be easily reduced to following: given a set of integers numbers and an integer target, is it possible to find a subset of numbers with sum equal to target?
Let me know if transition needs clarification.
It can be solved with DP in O(numbers.size * target) time. The idea is following
When numbers.size is 0, the only reachable sum is 0.
Suppose we have numbers == {1, 3}, in this case sums {0, 1, 3, 4} are available. What if we add another element to numbers, 4? Now, all old sums can still be reached and some new ones too: {0 + 4, 1 + 4, 3 + 4, 4 + 4}. Thus, for numbers == {1, 3, 4}, available sums are {0, 1, 3, 4, 5, 7, 8}.
In this fashion, adding number by number, you can build the list of reachable sums.
A working example (it doesn't handle negative numbers, but you can easily fix that)
boolean splittable(int[] numbers, int target) {
boolean[] reached = new boolean[target + 1];
reached[0] = true;
for (int number : numbers) {
for (int sum = target - 1; sum >= 0; --sum) {
if (reached[sum] && sum + number <= target) {
reached[sum + number] = true;
}
}
}
return reached[target];
}
Run it
System.out.println(splittable(new int[]{3, 1, 4}, 7)); // => true
System.out.println(splittable(new int[]{3, 1, 4}, 6)); // => false
edit
I just noticed the "recursion" part of the requirement. Well, DP can be rewritten as recursion with memoization, if that's the hard requirement. This would preserve runtime complexity.
edit 2
On groups. You have to assign elements divisible by 3 or 5 to respective groups before you proceed with the algorithm. Let's say, sum of all elements is s, sum of elements divisible by 3 is s3 and sum of elements divisible by 5 but not 3 is s5. In this case, after you assigned those 'special' elements, you have to split the rest that sum in one group is s/2 - s3 and in another s/2 - s5.
Very slow, but working solution:
static boolean canSplit(int[] arr, int lvl, int sum1, int sum2) {
if (arr.length == lvl) {
if (sum1 == sum2) {
return true;
} else {
return false;
}
}
if (arr[lvl] % 5 == 0) {
return canSplit(arr, lvl + 1, sum1 + arr[lvl], sum2);
} else if (arr[lvl] % 3 == 0) {
return canSplit(arr, lvl + 1, sum1, sum2 + arr[lvl]);
}
return canSplit(arr, lvl + 1, sum1 + arr[lvl], sum2) ||
canSplit(arr, lvl + 1, sum1, sum2 + arr[lvl]);
}
Call the function:
canSplit(arr, 0, 0, 0);
Code that would probably get me fired. But will work :D
Entirely recursive, equally deadly.
public boolean split53(int[] nums) {
return split_fn(0, nums, 0, 0, false, false);
}
public boolean split_fn(int start, int[] nums, int left, int right, boolean fiveLeft, boolean chosen) {
if (start >= nums.length) {
if (left == right) return true;
return false;
}
if (nums[start] % 5 == 0) {
if (!chosen) {
return split_fn(start + 1, nums, left + nums[start], right, true, true) || split_fn(start + 1, nums, left, right + nums[start], false, true);
} else {
return split_fn(start + 1, nums, left + ((fiveLeft) ? nums[start] : 0), right + ((!fiveLeft) ? nums[start] : 0), fiveLeft, chosen);
}
}
if (nums[start] % 3 == 0 && nums[start] % 5 != 0) {
if (!chosen) {
return split_fn(start + 1, nums, left + nums[start], right, false, true) || split_fn(start + 1, nums, left, right + nums[start], true, true);
} else {
return split_fn(start + 1, nums, left + ((!fiveLeft) ? nums[start] : 0), right + ((fiveLeft) ? nums[start] : 0), fiveLeft, chosen);
}
}
//standard case
return split_fn(start + 1, nums, left + nums[start], right, fiveLeft, chosen) || split_fn(start + 1, nums, left, right + nums[start], fiveLeft, chosen);
}
Here is the real recursive solution.
private boolean split2(int index, int[] nums, int sum1, int sum2) {
if (index >= nums.length) {
return sum1 == sum2;
}
if (split2(index + 1, nums, sum1 + nums[index], sum2)) {
return true;
}
if (split2(index + 1, nums, sum1, sum2 + nums[index])) {
return true;
}
return false;
}
This code goes through puting every element into one of the group. If in any combination the two groups are equal it returns true. No loops used and in only one function.
Best for all
edit: Your function takes 4 arguments as input whereas the question gets as input only the array. You have to specify that the desired function could be done using yours with the call split2(0,nums,0,0);
I don't know how fast or slow the following solution is. But precisely it is a recursive backtracking solution, which uses no loops as mentioned in the question.
Here is the code snippet:
public boolean split53(int[] nums) {
int start = 0, firstPart = 0, secondPart = 0;
if (split(start, nums, firstPart, secondPart)) {
return true;
}
return false;
}
public boolean split(int start, int[] nums, int firstPart, int secondPart) {
if (start >= nums.length) {
return (firstPart == secondPart);
}
if ((start + 1) < nums.length
&& (nums[start] % 3 != 0)
&& (nums[start + 1] % 5 != 0)
&& split(start + 2, nums, firstPart + nums[start], secondPart
+ nums[start + 1])) {
return true;
}
if ((start + 1) < nums.length
&& (nums[start + 1] % 3 != 0)
&& (nums[start] % 5 != 0)
&& split(start + 2, nums, firstPart + nums[start + 1],
secondPart + nums[start])) {
return true;
}
if ((nums[start] % 3 != 0)
&& split(start + 1, nums, firstPart + nums[start], secondPart)) {
return true;
}
if ((nums[start] % 5 != 0)
&& split(start + 1, nums, firstPart, secondPart + nums[start])) {
return true;
}
return false;
}
Hope it helps.
Related
I was trying one problem to count the number of triplets in an array whose sum is less than target value.
Input: [-1, 4, 2, 1, 3], target=5
Output: 4
Explanation: There are four triplets whose sum is less than the target:
[-1, 1, 4], [-1, 1, 3], [-1, 1, 2], [-1, 2, 3]
My Code
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target - arr[i] - arr[left] - arr[right];
if (targetDiff > 0)
{
count++;
right--;
}
else
{
left++;
}
}
}
// TODO: Write your code here
return count;
}
}
It produces the output of 3 where as correct value should be 4 as per the above given input. My logic was , say , x + y + z < targetSum , it implies (targetSum - (x + y + z) ) > 0. If this is true I will increase the count and then decrement the right pointer , since array is sorted. If its not true then I will increment the left pointer . But my logic does not cover the triplet {-1, 2, 3}.
Below is the correct code given by author.
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for (int i = 0; i < arr.length - 2; i++) {
count += searchPair(arr, target - arr[i], i);
}
return count;
}
private static int searchPair(int[] arr, int targetSum, int first) {
int count = 0;
int left = first + 1, right = arr.length - 1;
while (left < right) {
if (arr[left] + arr[right] < targetSum) {
count += right - left;
left++;
} else {
right--; // we need a pair with a smaller sum
}
}
return count;
}
public static void main(String[] args) {
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 0, 2, 3 }, 3));
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 4, 2, 1, 3 }, 5));
}
}
The author has used the concept , say x + y + z < targetSum , it implies x + y < targetSum - z . But I don't get the logic of line count += right - left; . How author use this one line to capture the count. If some one can give me the intution on how to reach this inference. Also what is wrong with my code and what can I do to correct it.
A first issue with your code is that :
you only decrease the right index if the sum is inferior to the target.
However, since you have ordered your list, well you will only be entering that case until left=right.
Quick example : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], target=14
if 1+2+10 <13:
then you will only decrease 10 until you reach 2 in your array
and then you proceed to iterate to the next i-index, here going from 0 to 1.
Meaning that: you will never get the solutions in between such as [1,3,9] and all the one that follows.
I hope it helps you see where there was an error in the logic, which was not from the statement : (targetSum - (x + y + z) ) > 0 but from the action you take according to the result (True/False).
Now, I am not sure there would be an easy way to adapt your code corrctly, because the main issue here is that you have iterate over 2 indexes at once (right and left).
Now regarding your author's answer :
The trick behind :
count += right - left;
goes back to the issue you had, if i tame my example, for
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
it is basically saying that, since the array is ordered, if the sum of two integers with the right one is inferior to target, then it will also be true for all integers inferior to right :
1+2+10<14 => 1+2+9<13
And this statement is true for all integers between left and right, so instead of doing a loop for which we already have the answer, he adds to count the differences between right and left, in other words, the number of integers in your array that will be greater than left and lower than right.
Now that i have explained that, you could use the same "trick" to your code:
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target -( arr[i] + arr[left] + arr[right]);
if (targetDiff > 0)
{
count += right - left;
left++;
}
else
{
right--;
}
}
}
// TODO: Write your code here
return count;
}
}
I tried to be as detailed as possible, hope it helps you understand better!
Given an int array that may contain duplicates. I need to find out whether the array can produce a sum with k elements?
I'm trying to use recursion for now but I'm not getting anywhere at the moment. I have a problem with getting the base-case right.
static boolean groupSum(int[] nums, int k, int sum) {
if (sum == 0)
return true;
if (k > nums.length || sum != 0)
return false;
if (groupSum(nums, k, sum - nums[k - k] - nums[k - k + 1] - nums[k - k + 2]))
return true;
if (groupSum(nums, k, sum - nums[k - k + 1] - nums[k - k + 2] - nums[k - k + 3]))
return true;
else
return false;
}
The base case of your recursive method is incorrect: sum == 0 isn't a sufficient condition you also have to check whether k == 0. If the sum is 0 but you still have to use a few more elements then the result true is incorrect.
The recursive part of the method has some mistakes in it as well. The number of elements summed up k never gets decremented.
Also, you have to track a position in the array. I mean you need to iterate over the array. And while iterating for each element there are only two options: apply it (decrement the k and subtract current value from the sum) or discard it. In both cases, you have to increment the position that you are passing as an argument.
That is how it could be fixed:
public static boolean groupSum(int[] nums, int k, int pos, int sum) {
if (sum == 0 && k == 0) {
return true;
}
if (sum < 0) {
return false;
}
boolean result = false;
for (int i = pos; i < nums.length; i++) {
boolean takeElement = groupSum(nums, k - 1, pos + 1, sum - nums[i]);
boolean discardElement = groupSum(nums, k, pos + 1, sum);
result = takeElement || discardElement;
if (result) { // a combination that yield the target sum was found
break;
}
}
return result;
}
There's another option how to implement this method. But caution: it will be slower and significantly increases memory consumption.
This approach requires creating a copy of the given array with a length decremented by 1 at each recursive method call and pass it as an argument. In this version, an element at position 0 is always used when the method is called, therefore it doesn't require to track the position in the array. The main logic remains the same: a new element can be used either to contribute the sum or can be discarded.
public static boolean groupSum(int[] nums, int k, int sum) {
if (sum == 0 && k == 0) {
return true;
}
if (sum < 0 || nums.length == 0) {
return false;
}
boolean takeElement = groupSum(Arrays.copyOfRange(nums, 1, nums.length), k - 1, sum - nums[0]);
boolean discardElement = groupSum(Arrays.copyOfRange(nums, 1, nums.length), k, sum);
return takeElement || discardElement;
}
public static void main(String[] args) {
// sum of 1, 2, 3, 4, 5 yields 15 - expected true
System.out.println(groupSum(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 5, 0, 15));
// it's impossible with only one element - expected false
System.out.println(groupSum(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 1, 0, 10));
// sum of 4, 5, 6 yields 15 - expected true
System.out.println(groupSum(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 3, 0, 15));
}
output
true
false
true
Consider the following serie:
1, 1, 2, 2, 4, 8, 32, 256, ...
I wrote this method in Java:
public static int Fibmul(int n){
if (n == 1) return 1;
else if (n == 0) return 0;
else if (n < 0) return -1; // -1 means 'nil'
else {
n = Fibmul(n - 2) * Fibmul(n - 1);
}
return n;
}
To calculate the serie just multiply the last two positions of the elements to obtain the next element, E.g Fibmul(4) should return 4 and Fibmul(6) should return 32.
But this code is wrong an I don't have more ideas, I have clear the algorithm over the paper but I don't know how to implement it.
Can anybody help me?
Thanks in advance.
You're not going to get any higher numbers if your starting numbers are 0 and/or 1.
If your starting numbers are 1 and 2, you will get something like the sequence you described.
public static int Fibmul(int n){
if (n == 1) return 2;
else if (n == 0) return 1;
else if (n < 0) return -1; // -1 means 'nil'
else {
n = Fibmul(n - 2) * Fibmul(n - 1);
}
return n;
}
This will give
1, 2, 2, 4, 8, 32, ...
It cannot start with 1,1,2 if you want to follow the rule you stated, because 1*1 does not equal 2.
NB: Your sequence is actually the ordinary Fibonacci series but with each term used as a power of 2.
Fibonacci: 0, 1, 1, 2, 3, 5, 13, ...
Fibmul: 2**0, 2**1, 2**1, 2**2, 2**3, 2**5, 2**13, ...
You simply need an extra solution for when n == 2 because otherwise you'll remain stuck with 1, 1, 1, 1, 1, ...
public static int Fibmul(int n) {
if (n == 2)
return 2;
if (n == 1)
return 1;
else if (n == 0)
return 0;
else if (n < 0)
return -1; // -1 means 'nil'
return Fibmul(n - 2) * Fibmul(n - 1);
}
Testing it works as expected
Fibmul(0) = 0
Fibmul(1) = 1
Fibmul(2) = 2
Fibmul(3) = 2
Fibmul(4) = 4
Fibmul(5) = 8
Fibmul(6) = 32
Fibmul(7) = 256
Fibmul(8) = 8192
Fibmul(9) = 2097152
I think you are missing the 2 value. This should return 2, and the rest is fine:
else if (n == 2) return 2;
See here: https://code.sololearn.com/ca22A0a236a2
public class Solution {
public ArrayList<Integer> plusOne(ArrayList<Integer> A) {
int n = A.size();
// Add 1 to last digit and find carry
A.set(n - 1, A.get(n - 1) + 1);
int carry = A.get(n - 1) / 10;
A.set(n - 1, A.get(n - 1) % 10);
// Traverse from second last digit
for (int i = n - 2; i >= 0; i--) {
if (carry == 1) {
A.set(i, A.get(i) + 1);
carry = A.get(i) / 10;
A.set(i, A.get(i) % 10);
}
}
// If carry is 1, we need to add
// a 1 at the beginning of vector
if (carry == 1)
A.add(0, 1);
return A;
}
}
Question is:
Given a non-negative number represented as an array of digits,
add 1 to the number ( increment the number represented by the digits ).
The digits are stored such that the most significant digit is at the head of the list.
Example:
If the vector has [1, 2, 3]
the returned vector should be [1, 2, 4]
as 123 + 1 = 124.
Wrong Answer. Your program's output doesn't match the expected output. You can try testing your code with custom input and try putting debug statements in your code.
Your submission failed for the following input:
A : [ 0, 0, 4, 4, 6, 0, 9, 6, 5, 1 ]
Your function returned the following :
0 4 4 6 0 9 6 5 2
The expected returned value :
4 4 6 0 9 6 5 2
Use below method
private ArrayList<Integer> recursiveCheckZero() {
if (arrayList.get(0) == 0) {
arrayList.remove(0);
recursiveCheckZero();
} else {
return arrayList;
}
}
This method will be used to zero at first position, it would be called recursively until all zeros get removed. and when there will be no zero at first position it will return final ArrayList of integers as actual result
int sum=0;
int carry=0;
int i=0;
while (i < A.size() - 1 && A.get(i) == 0) {
A.remove(i); //remove all zeroes in front
}
for(i=A.size()-1;i>=0;i--)
{
int n=A.get(i);
sum=n+carry;
if(i==A.size()-1)
{
sum = sum+1;
}
carry=sum/10;
sum=sum%10;
A.set(i,sum);
}
if (carry !=0)
A.add(0,1);
return A;
Basically, what I need is some kind of a mapping function that should map an integer (0 - N) to an index (0 - M). For N = 10, M = 3, the function should map:
1 -> 0, 2 -> 1, 3 -> 2, 4 -> 3, 5 -> 0, 6 -> 1, 7 -> 2, 8 -> 3, 9 -> 0 and 10 -> 1.
My brain is pretty dead so I ended up with some bull*&^% mapping :)
public int getIndexForNumber(int number, int maxIndex) {
int max = maxIndex;
while (maxIndex > 0) {
if (number % maxIndex-- == 0) {
return maxIndex;
}
}
return max;
}
Can anyone please direct me?
Why don't just return a remainder?
public int getIndexForNumber(int number, int maxIndex) {
return (number - 1) % maxIndex;
}
if negative numbers are allowed
public int getIndexForNumber(int number, int maxIndex) {
int x = (number - 1) % maxIndex;
if (x < 0)
x += maxIndex;
retrun x;
}
There is a pattern in the mapping function, which is that a number n is mapped to (n-1) mod (m+1). Using this, you can write the function as:
public int getIndexForNumber(int number, int maxIndex) {
return (number - 1) % (maxIndex + 1);
}