I am having trouble subtracting values from a single array. If I have the numbers 1, 2, 3, 4, 5 stored in an array, how can I find the difference?
For example 1-2-3-4-5 = -13
I know how to sum the values of an array but having trouble subtracting one array element from the next to get the correct answer.
int sum = 0;
if (operator == '+'){
for ( int j = 0; j < intArray.length; j++ ) {
sum += intArray[j];
}
}
if (operator == '-'){
for ( int j = 0; j < intArray.length; j++ ) {
sum += intArray[j] - intArray[j+1] ;
}
}
System.out.println("The answer is " + sum);
//This is a pretty simple way to solve it
public class Minimize {
public static int substractArrayValues(int [] q){
int val=0;
for (int i=0; i<q.length; i++){
if (i==0){
val=q[i];
}
else {
val=val-q[i];
}
}
return val;
}
public static void main(String[] args) {
int [] q={1,2,3,4,5};
System.out.println(substractArrayValues(q));
}
}
This will print -13
I assume you want to subtract 1-2-3-4-5 which is equal to -13.
So here comes your mistake sum+=intArray[j] - intArray[j+1] ;
Operation:-
Iteration 1:- sum=-1 which is (1-2) sum=-1
Iteration 2:sum=sum+(2-3) which is (-1+2-3) sum=-2
Iteration 3:sum=sum+(3-4) which is (-2+3-4) sum=-3
Iteration 4:sum=sum+(4-5) which is (-3+4-5) sum=-4
Iteration 5:sum=sum+(5-Garbage value or indexoutofbound exception)
sum=garbage value
Try using sum-=intArray[j];
With IntStream and a bit of functional programming
import java.util.Arrays;
import java.util.stream.IntStream;
int myArray[] = {1,2,3,4,5};
int sum = IntStream
// get all the indices
.range(0, myArray.length)
// for the 1st element use the +ve sign
// and for the rest use -ve sign: so it
// will generate 1,-2,-3,-4,-5
.map(i -> i == 0? myArray[i] : -myArray[i])
// add the generated elements using map: 1-2-3-4-5
.sum();
System.out.println(sum); // -13
You should start with a the sum at index 0 and then call -= to all the other elements. currently you are doing index - (index -1) which will fail since you don't check for out of bounds. Also the math will be wrong in your current implementation because you use values to subtract twice instead on once.
Take this array with your subtraction method A[1, 2, 3, 4]
sum = 0;
sum += 1 - 2;
sum is -1; (Correct)
sum += 2 - 3;
sum is (-1 + -1) = -2 (Wong, should be -4)
sum += 3 - 4;
sum is (-2 - 1) = -3 (Wrong should be -8)
sum += 4 - A[4] (ERROR index out of bounds)
Here is the implementation that subtracts the values once
if (operator == '-'){
sum = intArray.length > 0 ? intArray[0] : 0;
for ( int j = 1; j < intArray.length; j++ ) {
sum -= intArray[j];
}
}
We have to take the first value in the array, and then subtract or add the remaining values from and to it depending on the operator. This is done as shown below:
int sum, dif;
if(intArray.length >= 1){
sum = intArray[0];
dif = intArray[0];
}
if (operator == '+'){
if(intArray.length > 1){
for ( int j = 1; j < intArray.length; j++ ) {
sum += intArray[j];
}
}
System.out.println("The sum is = " + sum);
}
if (operator == '-'){
if(intArray.length > 1){
for ( int j = 1; j < intArray.length; j++ ) {
dif -= intArray[j];
}
}
System.out.println("The difference is = " + dif);
}
You always do a positive sum += on operator -.
But how about using the Stream-API instead?
IntStream.of(1, 2, 3, 4, 5)
.reduce(operatorFunction('-'))
.ifPresent(System.out::println);
with the following IntBinaryOperator-returning function:
static IntBinaryOperator operatorFunction(char operator) {
if (operator == '-') {
return (int1, int2) -> int1 - int2;
}
return (int1, int2) -> int1 + int2;
}
which prints -13 as you would expect. This is all you need. Note that you could also use IntStream.sum to achieve a simple sum. With the operatorFunction however you could also add * or รท later if you wish.
Another way to write the above code (with intermediate values):
int[] yourInputArray = {1, 2, 3, 4, 5};
char operator = '-';
OptionalInt = Stream.of(yourInputArray)
.reduce(operatorFunction(operator));
From here you can call orElse(0) or throw an exception with orElseThrow(() -> ...), etc. Just have a look at the OptionalInt-javadoc for your options. As soon as you move away from the primitive int you may want to exchange the code by using Stream, BinaryOperator<Integer> and Optional<Integer>.
By the way, there is also an IndexOutOfBoundException in your current code. But why messing with indexes and arrays, if you can use Streams and so few lines of code?
Related
I have to write a function that multiplies two numbers represented by two int arrays (so I can't use ArrayLists or something).
Each digit of a number is represented by an int between 0 and 9 in the array, no element should be greater than that.
The first element of the array represents the last digit of the number and so on, therefore the number 1234 would be {4,3,2,1} as an array in this function.
I thought multiplying those arrays that way would be similar to long multiplication, so I tried to implement it in a similar way: You multiply every digit of the first array with every digit of the second one and store the rest if the result is equal or greater to 10 and then add it to the next digit. However, I seem to have done something wrong in the code (maybe the calculation of the rest??) because the result of my function is not correct: I tested it with 190 times 86 (represented by the arrays {0,9,1} and {6,8}) and get 15342 ({2,4,3,5,1}) instead of the actual result 16340 (which would be {0,4,3,6,1}).
Can somebody here help me out with this please? This is my code:
import java.util.Arrays;
public class MultiplyArrays {
static int[ ] times(int[ ] a, int[ ] b) {
int[] arr = new int[a.length + b.length - 1];//arr should be the result of a*b. The result shouldn't be shorter than that
int tmp = 0;//stores the rest of two-digit numbers
for(int i = b.length - 1; i >= 0; i--){
for(int j = 0; j < a.length; j++){//should multiply all digits of a with the current index of b
arr[i + j] = (arr[i + j] + (b[i] * a[j] + tmp)) % 10;//sets the value of the (i+j)th index in arr to the multiplication of two numbers from a and b adding the rest tmp.
if((arr[i + j] + b[i] * a[j] + tmp) < 10){//if this number is less than 10, there is no rest
tmp = 0;
}
else{//otherwise, the rest should be the second digit
tmp = (((arr[i + j] + (b[i] * a[j] + tmp))) - ((arr[i + j] + (b[i] * a[j] + tmp)) % 10)) / 10;//something in the formula for the rest is wrong, I guess
}
}
}
if(tmp != 0){//if the last number of the array containing the result is calculated and there still is a rest, a new array with one more digit is created
int[] arr2 = new int[arr.length + 1];
for(int i = arr.length - 1; i >= 0; i--){//the new array copies all numbers from the old array
arr2[i] = arr[i];
arr2[arr2.length - 1] = tmp;//the last space is the rest now
}
return arr2;
}
else{//if there is no rest after calculating the last number of arr, a new array isn't needed
return arr;
}
}
public static void main(String[] args) {//test the function with 190 * 86
int[] a = {0,9,1};
int[] b = {6,8};
System.out.println(Arrays.toString(times(a,b)));
}
}
Maybe this comes from the fact that your indices in the for-loops of the times()-method are incrementing AND decrementing.
The i is going down and the j is going up.
Also, in the second for loop, you should only increment to 'a.length - 1', not to 'a.length'.
Arbitrary precision multiplication is more complex than it seems, and contains corner cases (like one and zero). Fortunately, Java has an arbitrary precision type; BigInteger. In order to use it here, you would need to create two additional methods; one for converting an int[] to a BigInteger, and the second the convert a BigInteger to an int[].
The first can be done with a single loop adding each digit at index i (multiplied by 10i) to a running total. Like,
private static BigInteger fromArray(int[] arr) {
BigInteger bi = BigInteger.ZERO;
for (int i = 0, pow = 1; i < arr.length; pow *= 10, i++) {
bi = bi.add(BigInteger.valueOf(arr[i] * pow));
}
return bi;
}
And the second can be done a number of ways, but the easiest is simply to convert the BigInteger to a String to get the length() - once you've done that, you know the length of the output array - and can populate the digits in it. Like,
private static int[] toArray(BigInteger bi) {
String s = bi.toString();
int len = s.length();
int[] r = new int[len];
for (int i = 0; i < len; i++) {
r[i] = s.charAt(len - i - 1) - '0';
}
return r;
}
Finally, call those two methods and let BigInteger perform the multiplication. Like,
static int[] times(int[] a, int[] b) {
BigInteger ba = fromArray(a), bb = fromArray(b);
return toArray(ba.multiply(bb));
}
Running your original main with those changes outputs (as expected)
[0, 4, 3, 6, 1]
Well, your thought would work with addition, but on multiplication you multiply each digit of one with the whole number of the other and step one digit to the left (*10) each time you change the multiplication digit of the first number.
So you might brought something into confusion.
I just solved it in a more structured way, running the debugger will hopefully explain the process. In the solutions you can remove the trailing / leading zero by checking the digit if 0 and replace the array with one of length - 1.
The solutions are:
With conditions mentioned (numbers in reverse order):
public static void main(String[] args) {
int[] a = {3,2,1};
int[] b = {9,8};
System.out.println("Result is: " + Arrays.toString(calculate(a, b)));
}
private static int[] calculate(int[] a, int[] b) {
// final result will be never longer than sum of number lengths + 1
int[] finalResult = new int[a.length + b.length + 1];
int position = 0;
for(int i = 0; i < a.length; i++) {
int[] tempResult = multiplyWithOther(a[i], b);
addToFinalResult(finalResult, tempResult, position);
position++;
}
return finalResult;
}
private static int[] multiplyWithOther(int number, int[] otherArray) {
// The number cannot be more digits than otherArray.length + 1, so create a temp array with size +1
int[] temp = new int[otherArray.length + 1];
// Iterate through the seconds array and multiply with current number from first
int remainder = 0;
for(int i = 0; i < otherArray.length; i++) {
int result = number * otherArray[i];
result += remainder;
remainder = result / 10;
temp[i] = result % 10;
}
// Add remainder (even if 0) to start
temp[temp.length - 1] = remainder;
return temp;
}
private static void addToFinalResult(int[] finalResult, int[] tempResult, int position) {
int remainder = 0;
for(int i = 0; i < tempResult.length; i++) {
int currentValue = tempResult[i];
int storedValue = finalResult[i + position];
int sum = storedValue + currentValue + remainder;
remainder = sum / 10;
finalResult[i + position] = sum % 10;
}
finalResult[position + tempResult.length] = remainder;
}
And with numbers in normal order in array:
public static void main(String[] args) {
int[] a = {1,2,3,6};
int[] b = {8, 9, 1};
System.out.println("Result is: " + Arrays.toString(calculate(a, b)));
}
private static int[] calculate(int[] a, int[] b) {
// final result will be never longer than sum of number lengths + 1
int[] finalResult = new int[a.length + b.length + 1];
int positionFromEnd = 0;
for(int i = 1; i <= a.length; i++) {
int[] tempResult = multiplyWithOther(a[a.length-i], b);
addToFinalResult(finalResult, tempResult, positionFromEnd);
positionFromEnd++;
}
return finalResult;
}
private static int[] multiplyWithOther(int number, int[] otherArray) {
// The number cannot be more digits than otherArray.length + 1, so create a temp array with size +1
int[] temp = new int[otherArray.length + 1];
// Iterate through the seconds array and multiply with current number from first
int remainder = 0;
for(int i = 1; i <= otherArray.length; i++) {
int result = number * otherArray[otherArray.length - i];
result += remainder;
remainder = result / 10;
temp[otherArray.length - i +1] = result % 10;
}
// Add remainder (even if 0) to start
temp[0] = remainder;
return temp;
}
private static void addToFinalResult(int[] finalResult, int[] tempResult, int positionFromEnd) {
int remainder = 0;
for(int i = 1; i <= tempResult.length; i++) {
int currentValue = tempResult[tempResult.length - i];
int storedValue = finalResult[finalResult.length - positionFromEnd - i];
int sum = storedValue + currentValue + remainder;
remainder = sum / 10;
finalResult[finalResult.length - positionFromEnd - i] = sum % 10;
}
finalResult[finalResult.length - positionFromEnd - tempResult.length - 1] = remainder;
}
Given an array of integers and a sum, the task is to print all subsets of given array with sum equal to given sum.
Example:
Input : arr[] = {1, 2, 3, 4, 5}
sum = 10
Output : [4 3 2 1]
[5 3 2]
[5 4 1]
Input : arr[] = {-1, 2, 3, 4, 5}
sum = 10
Output : [5 3 2]
[5 4 2 -1]
I have done that using dynamic programming in pseudo polynomial time. This is an extension of subset sum problem, which only takes care of deciding whether such a subset exist or not. My solution below works for both positive and negative numbers for the subset sum problem. However, it is not able to print the subsets correctly if the array contains negative numbers.The program is-
import java.util.ArrayList;
// sum problem
class GFG {
static boolean subset[][];
// Returns true if there is a subset of
// set[] with sun equal to given sum
static boolean isSubsetSum(int set[],
int n, int sum) {
// The value of subset[i][j] will be
// true if there is a subset of
// set[0..j-1] with sum equal to i
subset = new boolean[n + 1][sum + 1];
// Fill the subset table in botton
// up manner
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
if (j == 0) {
subset[i][j] = true;
} else if (i <= 0 && sum >= 1)
subset[i][j] = false;
else if (set[i - 1] > j)
subset[i][j] = subset[i - 1][j];
else {
if (set[i - 1] >= 0)
subset[i][j] = subset[i - 1][j] || subset[i - 1][j - set[i - 1]];
else
subset[i][j] = subset[i - 1][j] || subset[i - 1][j + set[i - 1]];
}
}
}
// uncomment this code to print table
// for (int i = 0; i <= sum; i++)
// {
// for (int j = 0; j <= n; j++)
// System.out.println (subset[i][j]);
// }
return subset[n][sum];
}
/* Driver program to test above function */
public static void main(String args[]) {
int set[] = {1, 2, 3, 4, 5};
int sum = 10;
int n = set.length;
if (isSubsetSum(set, n, sum) == true)
System.out.println("Found a subset"
+ " with given sum");
else
System.out.println("No subset with"
+ " given sum");
System.out.println("Done");
ArrayList<Integer> list = new ArrayList<>();
printSubsets(set, n, sum, list);
System.out.println("Finished");
}
static void display(ArrayList<Integer> v) {
System.out.println(v);
}
private static void printSubsets(int[] set, int i, int sum, ArrayList<Integer> list) {
if (i == 0 && sum != 0 && subset[0][sum]) {
list.add(set[i]);
display(list);
list.clear();
return;
}
// If sum becomes 0
if (i == 0 && sum == 0) {
display(list);
list.clear();
return;
}
// If given sum can be achieved after ignoring
// current element.
if (subset[i - 1][sum]) {
// Create a new vector to store path
ArrayList<Integer> b = new ArrayList<>();
b.addAll(list);
printSubsets(set, i - 1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= set[i - 1] && subset[i - 1][sum - set[i - 1]]) {
list.add(set[i - 1]);
printSubsets(set, i - 1, sum - set[i - 1], list);
}
}
}
How this code can be modified to work for negative numbers as well?
Your solutions assumes that all values are positive, so the dynamic programing array subset is filled with the values of j that are positive, but you need to take into account negative sums now.
What you need to do is to change the loop limits of j to fill the dynamic programing array to
for (int j = negative_sum; j <= positive_sum; j++)
Where negative_sum is the sum of all the negative values and positive_sum is the sum of all the positive ones.
For more details read the wikipedia page for the Subset Sum Problem here where this step is explained.
Since you have to print ( or generate ) all possible subset of given set (containing both positive and negative integers) which have summation equal to sum, what you can do is :
try to represent each position of set as binary representation of 0 and 1, where 1 indicates that element at that position is taken and 0 indicates that element at that position is not taken into account.
Find the summation of all positions where there is 1. If the summation of these values is exactly equals to the given sum, then print that subset.
So, overall time complexity is O(2 ^ n), where n is length of given set.
You may look at following implementation.
import java.util.Arrays;
public class PerfectSum {
public static void printSubsets(int[] set, int n, int sum) {
int totalSubSets = (1 << n);
for (int i = 1; i < totalSubSets; ++i) { // loop over all possible subsets
int curSum = 0;
for (int j = n - 1; j >= 0; --j) {
if (((i >> j) & 1) > 0) { // if bit at jth position is 1 take that value
curSum +=set[j];
}
}
if (curSum == sum) { // valid subset found, then print it
for (int j = n - 1; j >= 0; --j) { // looping in reverse order to print set in decreasing order
if (((i >> j) & 1) > 0) { // if bit at jth position is 1 take that value
System.out.print(set[j] + " ");
}
}
System.out.println("");
}
}
}
public static void main(String[] args) {
int set[] = {-1, 2, 3, 4, 5};
Arrays.sort(set); // To print in non increasing order
int sum = 10;
int n = set.length;
printSubsets(set, n, sum);
}
}
You can subtract the minimum negative number of the array to the entire set, making the numbers in the array positive. Then apply dynamic programming.
I have the following code for subset sum which is suitable for integers. How to extend this code to double data type input? for example, how to extend this same code when the input is 1.01,2.65,3.08,4.07,5.12 (say) and output is 15.62 (say).These inputs and out are example even if they vary the code should work.
// A Java program to count all subsets with given sum.
import java.util.ArrayList;
public class subset_sum
{
// dp[i][j] is going to store true if sum j is
// possible with array elements from 0 to i.
static boolean[][] dp;
static void display(ArrayList<Integer> v)
{
System.out.println(v);
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
static void printSubsetsRec(int arr[], int i, int sum,
ArrayList<Integer> p)
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if (i == 0 && sum != 0 && dp[0][sum])
{
p.add(arr[i]);
display(p);
p.clear();
return;
}
// If sum becomes 0
if (i == 0 && sum == 0)
{
display(p);
p.clear();
return;
}
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
ArrayList<Integer> b = new ArrayList<>();
b.addAll(p);
printSubsetsRec(arr, i-1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i] && dp[i-1][sum-arr[i]])
{
p.add(arr[i]);
printSubsetsRec(arr, i-1, sum-arr[i], p);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
static void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
dp = new boolean[n][sum + 1];
for (int i=0; i<n; ++i)
{
dp[i][0] = true;
}
// Sum arr[0] can be achieved with single element
if (arr[0] <= sum)
dp[0][arr[0]] = true;
// Fill rest of the entries in dp[][]
for (int i = 1; i < n; ++i)
for (int j = 0; j < sum + 1; ++j)
dp[i][j] = (arr[i] <= j) ? (dp[i-1][j] ||
dp[i-1][j-arr[i]])
: dp[i - 1][j];
if (dp[n-1][sum] == false)
{
System.out.println("There are no subsets with" +
" sum "+ sum);
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
ArrayList<Integer> p = new ArrayList<>();
printSubsetsRec(arr, n-1, sum, p);
}
//Driver Program to test above functions
public static void main(String args[])
{
int arr[] = {1, 2, 3, 4, 5};
int n = arr.length;
int sum = 10;
printAllSubsets(arr, n, sum);
}
}
Output:[4, 3, 2, 1] [5, 3, 2] [5, 4, 1]
I found answer to this question by simply converting double to integer by calculating decimal places and multiply it by 100(say) as the algorithm uses addition this change does not affect final values in that case I divided the final value by 100 to get the result and displayed it in double data type
For the PermCheck codility test, I coded one solution (please see below) but it only really solved the example given in the codility test because there are only a few values in the array and small values. I also added code below which scored 100%, which is code I found on the internet. That code looks very different from mine and I couldn't work out how he/she was able to get the answer. Could someone please explain the code step by step and how it results in the answer please.
Codility Test:
PermCheck
Check whether array A is a permutation.
A non-empty zero-indexed array A consisting of N integers is given.
A permutation is a sequence containing each element from 1 to N once, and only once.
For example, array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
A[3] = 2
is a permutation, but array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
is not a permutation, because value 2 is missing.
The goal is to check whether array A is a permutation.
Write a function:
class Solution {
public int solution(int[] A);
}
that, given a zero-indexed array A, returns 1 if array A is a permutation and 0 if it is not.
For example, given array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
A[3] = 2
the function should return 1.
Given array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
the function should return 0.
Assume that:
N is an integer within the range [1..100'000];
Each element of array A is an integer within the range [1..1'000'000'000].
Complexity:
Expected worst-case time complexity is O(N)
Expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
100% Score Solution (found from internet):
public static final int NOT_PERMUTATION = 0;
public static final int PERMUTATION = 1;
// (4,1,3,2) = 1
// (4,1,3) = 0
// (1) = 1
// () = 1
// (2) = 0
public int PermSolution(int[] A) {
// write your code in Java SE 8
int[] mark = new int[A.length + 1];
int counter = 0;
for (int i = 0; i < A.length; ++i) {
int value = A[i];
if(value >= mark.length) {
return NOT_PERMUTATION;
}
if(mark[value] == 0) {
mark[value]=1;
++counter;
} else {
return NOT_PERMUTATION;
}
}
return counter == A.length ? PERMUTATION : NOT_PERMUTATION;
}
My Solution:
public int PermSolution(int[] A)
{
int perm = 1;
Arrays.sort(A);
if (A[0] != 1) return 0;
for (int i = 0; i < A.length; i++)
{
if (A[i] + 1 == A[i + 1])
{
return perm;
}
if (A[i] + 1 != A[i + 1])
{
return 0;
}
}
return perm;
}
Using Arrays.sort() is kind of original, that's not how I would have done it though.
To comment your code, it's probably isn't working because of this : return perm;
Let's say you have this Array which is not a permutation:
A[0] = 4
A[1] = 1
A[2] = 2
One you execute Arrays.sort(A), you'll have this :
A[0] = 1
A[1] = 2
A[2] = 4
Now let's execute your code :
if (A[0] != 1) return 0;
A[0] is indeed equal to 1
Next, for i==0 we have :
if (A[i] + 1 == A[i + 1])
{
return perm;
}
A[i] + 1 is equal 2 and A[i+1] is also equal to 2
the condition being true, you execute a return perm; and thus, you end your execution with a return 1.
Actually, as long as your array contains 1 and 2, this function will always return 1
For it to work, you'll have to check all of the array before actually returning a value.
This should work :
public int PermSolution(int[] A)
{
int perm = 1;
Arrays.sort(A);
if (A[0] != 1) return 0;
for (int i = 0; i < A.length; i++)
{
if (A[i] + 1 != A[i + 1])
{
return 0;
}
}
return perm;
}
To optimize it even further, this should work as well :
public int PermSolution(int[] A)
{
Arrays.sort(A);
for (int i = 0; i < A.length; i++)
{
if (A[i] != i+1)
{
return 0;
}
}
return 1;
}
Why don't we avoid Arrays.sort(A) in order to gain the computation efficiency by below:
public static int PermSolution(int[] A)
{
int len=A.length;
if(len==1)
return A[0]==1 ? 1 : 0;
BitSet set=new BitSet(len+2);
for (int i = 0; i < len; i++)
{
if(A[i]>len || set.get(A[i]))
return 0;
set.set(A[i]);
}
return set.nextClearBit(1)==(len+1) ? 1 : 0;
}
Here is some solution that I have developed. Not sure about constraints, if someone can help to test it against them. Thanks people!
private static int solution(int[] arr) {
int perm=1;
boolean b=false;
Arrays.sort(arr);
int i=0;
while (i<=arr.length) {
if(i < arr.length-2)
b = arr[i+1]-1 == (arr[i]);
if(b) {
System.out.println("if " + i);
i++;
perm=1;
}else {
System.out.println("else " + i);
perm = 0;
break;
}
}
return perm;
}
I am trying to write a DP solution for the problem: count total number of sub-sequences possible of an array whose elements' sum is divisible by k.
I have written the following solution. But it is not giving the correct result. Like in the following code snippet, the array is {1, 2, 1} and k = 3. So expected total number of sub sequences divisible by 3 is 2, but the actual result is 3 which is clearly incorrect.
Please point out my mistake.
private int countDP(int[] a, int k)
{
int L = a.length;
int[][] DP = new int[L][k];
for(int i = 0; i < DP.length; i++)
{
for(int j = 0; j < DP[0].length; j++)
DP[i][j] = -1;
}
int res = _countDP(a, k, DP, 0, 0);
return res;
}
private int _countDP(int[] a, int k, int[][] DP, int idx, int m) //Not giving the correct result.
{
if(idx == a.length)
return m == 0 ? 1 : 0;
if(DP[idx][m] != -1)
return DP[idx][m];
int ans = 0;
ans = _countDP(a, k, DP, idx + 1, m);
ans += _countDP(a, k, DP, idx + 1, (m + a[idx]) % k);
return DP[idx][m] = ans;
}
public static void main(String[] args)
{
CountSubnsequences cs = new CountSubnsequences();
int[] a = {1, 2, 1};
int k = 3;
int total1 = cs.countDP(a, k);
System.out.println("Total numeber of sub sequences: " + total1);
}
Let s denote a sequence of length N, and K be a given divisor.
dp[i][j] = the number of subsequences of s[0..i] with remainder equal to j. We will compute dp for all 0 <= i < N and 0 <= j < K.
dp[i][j] = 0 for all (i, j)
dp[0][0] += 1
dp[0][s[0] mod K] += 1
for i = 1 .. N - 1
for j = 0 .. K - 1
dp[i][j] = dp[i - 1][j]
for j = 0 .. K - 1
dp[i][(j + s[i]) mod K] += dp[i - 1][j]
The result is dp[N - 1][0]
Python code of #piotrekg2 solution.
Looks good!
from typing import List
# dp[i][j] = the number of subsequences of length i with remainder equal to j.
def count_subseq(s: List[int],k):
n = len(s)
dp = [0]*k
dp[0] = 1 # i=0, remainder=0, only 1 subseq
for i in range(1,n+1):
dp2 = dp.copy() # copy previous i-length results: results without s[i] in subseq
for j in range(k):
dp2[(j+s[i-1])%k] += dp[j]
dp = dp2
return dp[0]
if __name__ == '__main__':
print(count_subseq([2,3,5,8],5))
print(count_subseq([5,5,5],5))
Faced the same issue. But ended up getting an answer.
The answer returning will be always 1 more than the total possible subsequences. This is because we know that 0 is always being a valid answer. So, if let's say you do not pick any single element from the array, then also the sum=0. So, it considers it as a valid answer and increments our answer by 1. So, to get the actual answer Just decrement the returned value by 1.
int fun(int i,int s)
{
if(i==1){
if(s-a[i]!=0 && (s-a[i])%k==0)
return 1;
else
return 0;}
else{
if((s-a[i])%k==0){
return 1+fun(i-1,s-a[i])+fun(i-1,s);
}
else{
return fun(i-1,s-a[i])+fun(i-1,s);
}
}
}