longest Flat Sequence - recursion problem - java

First of all I'm a beginner programmer and I'm pretty sure I have quite a few errors in the code.
I'm stuck in code in the exercise,
sequence flat of integers if all the numbers in it are the same number or the series consists of two consecutive number,
I need to write a recursive method which receives an array of integers, and returns the length of the maximum subset which is a flat series.
For example for this array:
(4, 5, 6, 5, 4, 3)
The method will return 3. Since the sub-arrays that make up the flat series in the array are:
(4, 5) - Length 2.
(5, 6, 5) - Length 3.
(5, 4) - Length 2.
(4, 3) - Length 2.
The longest flat sub-series in the array is 3 in length, which is the value to be returned.
public static int longestFlatSequence (int[] arr)
{
return lengthFlat (arr, 0, 0);
}
private static int lengthFlat (int[] arr, int i, int max)
{
if (arr.length >= 1)
{
return arr.length;
}
if (i + 1 <= arr.length -1)
{
if (arr[i] == arr[i+1] || arr[i] + 1 == arr[i+1])
{
int val = lengthFlatSequence(arr,i,i+1);
if (val > max)
{
max = val;
}
}
return lengthFlat(arr, i+1, max);
}
return max;
}
private static int lengthFlatSequence(int[] arr, int i, int curr)
{
if (i == arr.length - 1)
{
return curr;
}
int min = 0;
if (arr[i] < arr[i+1])
{
min = arr[i];
}else{
min = arr[i+1];
}
if (min == arr[curr] || min + 1 == arr[curr])
{
return lengthFlatSequence(arr, i, curr);
}else{
return curr;
}
}
Please help me fix the code.
Thank you!

Related

Java recursion odd of sum

We have to find sum of array and then return if the value is odd (boolean) using recursion
A = {87, 31, 15, 25, 10, 15, 21, 75)
methodname(A, pos) //position is 0 at the begining
i did this so far, but i'm way off since i can't sum and return boolean in the same line
if (pos == array.length-1) {
return A[pos] % 2 != 0
} else {
if (pos < A.length - 1)
return A[pos] + methodname(A, pos + 1) % 2 == 1;
}
public static void main(String[] args) {
System.out.println(isSumOdd(new int[]{3, 3, 4}, 0));
}
private static boolean isSumOdd(int[] arr, int pos) {
return pos == arr.length - 1
? arr[pos] % 2 != 0
: isSumOdd(arr, pos + 1) ^ arr[pos] % 2 != 0; //Sum of 2 numbers can be odd iff exactly one of them is odd.
}
You can try using the following approach (syntax might be wrong, treat the following as pseudo code):
// gives whether the sum from i to end
// is even or odd
Boolean sumIsEven(int[] arr, int i ){
//base case
if(arr.length-1==i){
return arr[i]%2 ==0;
}
if(arr[i]%2 == 0){
return sumIsEven(arr, i +1);
}else{
// arr[i] is odd
return !sumIsEven(arr, i +1);
}
}
But this will give only if the whole sum is odd/even

Dynamic programming : perfect sum with negative numbers

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.

Subset sum for double data-type?

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

How to manage recursive function?

I need to write a recursive function that gets 4 parameters.
The 1st one is array. the 2nd one - left index, the 3rd one a right index and "K" index. "K" index is a cell in array , and the lrft index points to the start and the right one points to the end.
An array may contain such digitalis as zeros and ones. The method returns the maximum length of a sequence of ones that contain the cell k.
Here the example of the result that I need to get:
public static void main(String[] args) {
int[] A = {1,1,1,0,1,1,0,1,1,1,1,1,0,1,1};
System.out.println(floodOnes(A,0, A.length-1, 9)); // 5 output
System.out.println(floodOnes(A,0, A.length-1, 3)); // 0 output
System.out.println(floodOnes(A,0, A.length-1, 0)); // 3 output
System.out.println(floodOnes(A,0, A.length-1, 14)); // 2 output
}
public static int floodOnes(int [] A,int left, int right, int k){
//some logic
}
Here is my implementation:
public class Program {
public static void main(String[] args) {
int[] A = {1,1,1,0,1,1,0,1,1,1,1,1,0,1,1};
System.out.println(floodOnes(A,0,A.length-1, 9));
}
public static int floodOnes(int [] A,int left, int right, int k){
if (left != k) left+=1;
if (right != k) right-=1;
if (left == k && right == k) return A[k]; //condition when the recursive call stops
int res = floodOnes(A, left, right, k);
if (A[left] == 1 && A[right] == 1)
return res = A[left] + A[right]; //count ones
else return res;
}
}
But my solution not working properly.
In this rows:
if (A[left] == 1 && A[right] == 1)
return res = A[left] + A[right]; //count ones
If one of the conditions isn`t executed once, the following returns shouldn't add ones to result variable.
And I don't know how to do it.
I proved my comment wrong. Here is a recursive method with the 4 parameters mentioned in the question that indeed solves the problem.
public static int floodOnes(int[] a, int left, int right, int k) {
if (0 <= left && left <= k && k <= right && right < a.length) {
// is there a 0 between left (inclusive) and k (exclusive)?
int i = left;
while (i < k && a[i] == 1) {
i++;
}
if (i < k) {
assert a[i] == 0;
return floodOnes(a, i + 1, right, k);
}
// is there a 0 between k (exclusive) and right (inclusive)?
i = right;
while (i > k && a[i] == 1) {
i--;
}
if (i > k) {
assert a[i] == 0;
return floodOnes(a, left, i - 1, k);
}
// no zero found, a[k] not checked, though
if (a[k] == 0) {
return 0;
} else {
return right - left + 1;
}
} else {
throw new IllegalArgumentException("Expected " + left + " <= " + k + " <= " + right + " < " + a.length);
}
}
With this method, the first main method in your question prints the expected:
5
0
3
2
I really don’t see a point in solving the problem in this way, so I am far from sure this was what was intended. I’d prefer a non-recursive solution, or if it just needs to be recursive somehow, then the solution in Grzegorz Górkiewicz’ answer.
You can decompose this problem into 2 functions.
The first will count elements on the left-hand side, the latter on the right-hand side. Both use recursion.
public static int floodOnes(int[] A, int left, int right, int k) {
return checkLeft(A, left, k-1, A[k]) + 1 + checkRight(A, right, k+1, A[k]);
}
public static int checkLeft(int[] A, int leftBoundary, int k, int number) {
if (k < 0 || A[k] != number || k < leftBoundary)
return 0;
return 1 + checkLeft(A, leftBoundary, k-1, number);
}
public static int checkRight(int[] A, int rightBoundary, int k, int number) {
if(k >= A.length || A[k] != number || k > rightBoundary)
return 0;
return 1 + checkRight(A, rightBoundary, k+1, number);
}
I assume:
that 0 <= left <= k <= right < A.length;
that the solitary number should be counted as 1 (sequence of length 1) unlike your example. If you want it to be counted as 0, add if(A[k] != 1) return 0; or a similar condition in your floodOnes method.
Therefore:
System.out.println(floodOnes(A, 0, A.length - 1, 9)); // prints 5
System.out.println(floodOnes(A, 0, A.length - 1, 3)); // prints 1
System.out.println(floodOnes(A, 0, A.length - 1, 0)); // prints 3
System.out.println(floodOnes(A, 0, A.length - 1, 14)); // prints 2
Besides left and right parameters can be used for some input exceptions
(e.g. k > A.length).
Since you are looking for - the maximum length of a sequence of ones that contain the cell k. A simple and concise code to achieve this can be as follows.
public static void main(String[] args) {
int[] A = {1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1};
System.out.println(floodOnes(A, 0, A.length - 1, 9)); // prints 5
System.out.println(floodOnes(A, 0, A.length - 1, 3)); // prints 0
System.out.println(floodOnes(A, 0, A.length - 1, 0)); // prints 3
System.out.println(floodOnes(A, 0, A.length - 1, 14)); // prints 2
}
public static int checkLeft(int[] A, int k) {
return (k < 0 || A[k] != 1) ? 0 : 1 + checkLeft(A, k - 1);
}
public static int checkRight(int[] A, int k) {
return (k > (A.length - 1) || A[k] != 1) ? 0 : 1 + checkRight(A, k + 1);
}
public static int floodOnes(int[] A, int left, int right, int k) {
return (A[k] != 1) ? 0 : checkLeft(A, k - 1) + 1 + checkRight(A, k + 1);
}
It outputs the desired result.
5
0
3
2

How to iterate over array of integers to find a sequence based on an O(N) solution?

I saw following question and tried to find an answer for that.
Question: Given a sequence of positive integers A and an integer T, return whether there is a *continuous sequence* of A that sums up to exactly T
Example
[23, 5, 4, 7, 2, 11], 20. Return True because 7 + 2 + 11 = 20
[1, 3, 5, 23, 2], 8. Return True because 3 + 5 = 8
[1, 3, 5, 23, 2], 7 Return False because no sequence in this array adds up to 7
Note: We are looking for an O(N) solution. There is an obvious O(N^2) solution which is a good starting point but is not the final solution we are looking for.
My answer to above question is:
public class Tester {
public static void main(String[] args) {
int[] myArray = {23, 5, 4, 7, 2, 11};
System.out.println(isValid(myArray, 20));
}
public static boolean isValid(int[] array, int sum) {
int pointer = 0;
int temp = 0;
while (pointer < array.length)
{
for (int i = pointer; i < array.length; i++)
{
if (array[i] > sum)
break;
temp += array[i];
if (temp == sum)
return true;
else if (temp > sum)
break;
// otherwise continue
}
temp = 0;
pointer++;
}
return false;
}
}
I think my answer is O(N^2) which is not acceptable based on Question. Is there a solution based on O(N)?
You only need to loop once actually which is O(N).
Start adding from index 0 and once you exceed the sum start removing from the beginning of the array. if temp falls below sum continue looping.
public static boolean isValid(int[] array, int sum) {
int init = 0,temp = 0;
for (int i = 0; i < array.length; i++) {
temp += array[i];
while (temp > sum) {
temp -= array[init];
init++;
}
if (temp == sum)
return true;
}
return false;
}
What you should do is to have two indices (start and stop) then you increase stop until the sum is the required (and return true) or above. Then you increase start until the sum is the required (and return true or below. Then you repeat this until you reach the end of the array. You can update the sum incrementally (add the element when you increase stop and subtract when you increase start). This ought to be O(N).
Here's an example:
public class t {
public static void main(String[] args) {
int[] myArray = {23, 5, 4, 7, 2, 11};
System.out.println(isValid(myArray, 20));
}
public static boolean isValid(int[] array, int sum) {
int start = 0;
int stop = 0;
int tsum = 0;
while( true )
{
if( tsum < sum )
{
if( stop >= array.length )
break;
tsum += array[stop];
stop++;
}
else if( tsum > sum )
{
tsum -= array[start];
start++;
}
else if( tsum == sum )
return true;
// System.out.println(start + " -- " + stop + " => " + tsum);
}
return false;
}
}

Categories

Resources