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.
Related
You are given a city which lies on the x-axis. It has n buildings. The first building lies in x = 1 and has height h1, the second building lies on x = 2 and has height h2 and so on. You are a gigantic monster with a sword who wants to destroy the city. You are also a computer scientist at heart so you efficiency is the key, hence you want to destroy the city using minimum number of moves.
You can make one of the two moves :
1. Make a horizontal cut from x = L to x = R, cutting down the heights of the buildings from x = L to X = R by 1.
2. make a vertical cut at x = P, completely destroying the building at x = P thereby making its height zero.**
Note that : for the 1st type of move, every city in the range from L to R must have at least 1 height remaining, i.e. you cannot strike through an empty space.
Print the minimum number of moves needed to destroy the city.
Input
First line contains the number of test cases.
For each test case, the first line contains the number of buildings n.
Second line contains n integers denoting the heights of the building
Output
For every test case, print the minimum number of moves to destroy the city on a new line.
Notes
1 ≤ n ≤ 1000
0 ≤ hi ≤ 1000
Sample Input 0
2
5
2 2 2 3 3
5
10 2 10 2 10
Sample Output 0
3
5
I cannot figure out the approach to the question.
My code does not work for the following input:
1 1 1 2 4 5 7 7 8 9**
In my code i reduce the min value from all elements. Then find out the subarray between zeros and then compare the length of subarray(j-i) with the minimum value. if the length is less, then then we need to follow move 2, else move 1.
My code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.Scanner;
public class Main {
static int findmin(int arr[], int i, int j) {
int min = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
if (min > arr[k]) {
min = arr[k];
}
}
return min;
}
static void subtractmin(int arr[], int i, int j, int min) {
//if both the length of subarray and min are equal, we destroy separately
if (j - i <= min) {
for (int k = i; k < j; k++) {
// if
arr[k] = 0;
}
} else {
//subtract all
for (int k = i; k < j; k++)
// if
{
arr[k] -= min;
}
}
}
public static void main(String[] args) {
//int input[] = {10, 2, 10, 2, 10};// 5
//int input[] = {2, 2, 2, 3, 3};// 5
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while (t-- != 0) {
int zeros = 0;
int n = sc.nextInt();
int input[] = new int[n];
int min = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
input[i] = sc.nextInt();
if (min > input[i]) {
min = input[i];
}
if (input[i] == 0) {
zeros++;
}
}
//subtract minimum element from array
int count = 0;
if (zeros == 0) {
count += min;
subtractmin(input, 0, n, min);
} else {
count += min;
subtractmin(input, 0, n, min);
}
//traverse the array and findsubarrays between 0's
//1) if an element is surrounded by 0's it will be destroyed at once separately
// 2) also if length of subarray<min element, they all need to be destroyed separately
// 3) if min<length of subarray they need to be destroyed at once with count+=min
int i = 0, j = 0;
while (true) {
//move i to the first non zero element
for ( i = 0; i < n; i++) {
if (input[i] != 0) {
break;
}
}
//means whole array is 0;
if (i == n) {
System.out.println(Math.min(count, n - zeros));
break;
}
///start with the first non zero element and fin
for (j = i; j <= n; j++) {
if ( j == n || input[j] == 0) {
// take out min element
int minEle = findmin(input, i, j) ;
//if min lement is greater than subarray size, destroy separately
count += Math.min(minEle, j - i);
//System.out.println("count="+count+"min element="+minEle);
// subtract minimum element
subtractmin(input, i, j, minEle);
}
//if last elemnt is not zero
}
}
}
}
}
A possible hint here is that reducing a building to zero separates sections, which implies divide and conquer.
Let f(A, l, r) represent the optimal number of moves for the section of A indexed at [l, r]. Then:
f(A, l, r):
min(
# Reduce the whole section
# without separating it, using
# move 1, the horizontal cuts.
max(A[l..r]),
# Divide and conquer
1 + f(A, l, k-1) + f(A, k+1, r)
)
for all l ≤ k ≤ r
Except we don't need to try all ks, just one that points to max(A). Not removing max(A) implies we would need to either perform max(A) moves or we would have to remove it later.
JavaScript code:
function findMax(A, l, r){
let idx = l;
for (let i=l; i<=r; i++)
if (A[i] > A[idx])
idx = i;
return idx;
}
function f(A, l=0, r=A.length-1, memo={}){
if (l > r)
return 0;
if (l == r)
return 1;
const key = String([l, r]);
if (memo.hasOwnProperty(key))
return memo[key];
const k = findMax(A, l, r);
const best = Math.min(A[k], 1 + f(A, l, k-1, memo) + f(A, k+1, r, memo));
return memo[key] = best;
}
var As = [
[2, 2, 2, 3, 3],
[10, 2, 10, 2, 10],
[1, 1, 1, 2, 4, 5, 7, 7, 8, 9]
];
for (let A of As)
console.log(f(A));
The probleme you have is not in the code, but in the algorithm. If the size of a segment is small enough, effectivelly you have to perform move 2. However, this condition is not indispensable.
In practice, a simple recursive approach can solve this problem. In a given segment [k, l], after having substracted the min value, you simply have to perform:
n_moves = min (n, vmin + min_moves(x, k, l));
In the following, one function detects positions of the zeros and sum the moves corresponding to each segment
and another function is called for each segment with no zero inside.
The following code is in C++, but it is rather simple and should be easily translated to another language.
Output:
1 2 7 : 3
2 2 2 3 3 : 3
10 2 10 2 10 : 5
1 1 1 2 4 5 7 7 8 9 : 8
This code is provided for completeness. What is important is the algorithm itself.
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> get_zeros (const std::vector<int> &x, int k, int l) {
std::vector<int> zeros;
for (int i = k; i <= l; ++i) {
if (x[i] == 0) zeros.push_back(i);
}
return zeros;
}
int min_moves (std::vector<int> &x, int k, int l);
// This function is called after detection the position of the zeros -> no zero inside
int min_moves_no_zero (std::vector<int> &x, int k, int l) {
int n = l-k+1;
if (n == 0) return 0;
if (n == 1) return 1;
int vmin = 10000;
for (int i = k; i <= l; ++i) {
if (x[i] < vmin) vmin = x[i];
}
for (int i = k; i <= l; ++i) {
x[i] -= vmin;
}
int nm = std::min (n, vmin + min_moves(x, k, l));
return nm;
}
// This function detects positions of the zeros and sum the moves corresponding to each segment
int min_moves (std::vector<int> &x, int k, int l) {
auto zeros = get_zeros (x, k, l);
if (zeros.size() == 0) return min_moves_no_zero (x, k, l);
int start = k;
int total = 0;
for (int z = 0; z < zeros.size(); ++z) {
int end = zeros[z] - 1;
if (start != zeros[z]) {
total += min_moves_no_zero (x, start, end);
}
start = end + 2;
}
if (start <= l) {
total += min_moves_no_zero (x, start, l);
}
return total;
}
void print (const std::vector<int> &x) {
for (auto k: x) {
std::cout << k << " ";
}
}
int main() {
std::vector<std::vector<int>> input {
{1, 2, 7},
{2, 2, 2, 3, 3},
{10, 2, 10, 2, 10},
{1, 1, 1, 2, 4, 5, 7, 7, 8, 9}
};
for (auto& arr: input) {
auto save = arr;
int moves = min_moves (arr, 0, arr.size()-1);
print (save);
std::cout << " : " << moves << "\n";
}
}
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
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?
I was asked to take a HackerRank code test, and the exercise I was asked is the Max Common Array Slice. The problem goes as follows:
You are given a sequence of n integers a0, a1, . . . , an−1 and the
task is to find the maximum slice of the array which contains no more
than two different numbers.
Input 1 :
[1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 6, 2, 1, 8]
Result 1 : Answer is 10 because the array slice of (0, 9) is the
largest slice of the array with no more than two different numbers.
There are 10 items in this slice which are "1, 1, 1, 2, 2, 2, 1, 1, 2, 2".
2 different numbers for this slice are 1 and 2.
Input 2:
[53, 800, 0, 0, 0, 356, 8988, 1, 1]
Result 2: Answer is 4 because the slice of (1, 4) is the largest slice
of the array with no more than two different numbers. The slice (2, 5)
would also be valid and would still give a result of 4.
There are 4 items in this slice which are "800,0,0,0".
2 different numbers for this slice are 800 and 0.
Maximum common array slice of the array which contains no more than
two different numbers implementation in Java takes a comma delimited
array of numbers from STDIN and the output is written back to console.
The implementation I provide (below) works, however 3 test cases timeout in HR. Clearly, HR hides the test cases, so I could not see exactly the conditions the timeout was triggered or even the length of the timeout.
I'm not surprised of the timeout, though, given the asymptotic complexity of my solution. But my question is: how could my solution be improved?
Thanks in advance to all those that will help!
import java.io.*;
import java.lang.*;
import java.util.*;
import java.util.stream.*;
public class Solution {
public static void main(String args[] ) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
List<Integer> inputSequence = parseIntegerSequence(line);
int largestSliceSize = calculateLargestSlice(inputSequence);
System.out.println(largestSliceSize);
}
private static List<Integer> parseIntegerSequence(String input) {
if (input == null)
return new ArrayList();
return Arrays.asList(input.split("\\s*,\\s*"))
.stream()
.filter(item -> item.matches("^\\s*-?[0-9]+\\s*$"))
.map(item -> Integer.parseInt(item))
.collect(Collectors.toList());
}
private static int calculateLargestSlice(List<Integer> inputSequence) {
Map<Integer, Integer> temporaryMap = new HashMap<>();
int result = 0;
int startIndex = 0;
int uniqueItemCount = 0;
Integer[] array = inputSequence.toArray(new Integer[inputSequence.size()]);
while (startIndex < array.length) { // loop over the entire input sequence
temporaryMap.put(array[startIndex], startIndex);
uniqueItemCount++;
for (int j = startIndex + 1; j < array.length; j++) {
if (temporaryMap.get(array[j]) == null) {
if (uniqueItemCount != 2) {
temporaryMap.put(array[j], j);
uniqueItemCount++;
if (j == array.length - 1) {
result = Math.max(result, j - startIndex + 1);
startIndex = array.length;
break;
}
} else {
result = Math.max(result, j - startIndex);
int item = array[j-1];
int firstFoundIndex = 0;
for( int k=j-1; k>=0; k-- )
{
if( array[k] != item )
{
firstFoundIndex = k+1;
break;
}
}
startIndex = firstFoundIndex;
temporaryMap.clear();
uniqueItemCount = 0;
break;
}
} else if (temporaryMap.get(array[j]) != null) {
if (j == array.length - 1) {
result = Math.max(result, j - startIndex + 1);
startIndex = array.length;
break;
}
}
}
}
return result;
}
}
This is my answer in Java and it passed all the HackerRank test cases. Please feel free to comment if you find something wrong.
public static int maxCommonArraySlice(List<Integer> inputSequence) {
if(inputSequence.size() < 2) return inputSequence.size(); // I'm doubting this line should be <= 2
List<Integer> twoInts = new LinkedList<>();
twoInts.add(inputSequence.get(0));
int start = 0;
int end = inputSequence.size();
int count = 0;
int max_length = 0;
while(start < end) {
if(twoInts.contains(inputSequence.get(start))) {
count++;
start++;
}
else if(twoInts.size() == 1) {
twoInts.add(inputSequence.get(start));
}
else { // twoInts.size() is 2
count = 0;
start--;
twoInts.set(0, inputSequence.get(start));
twoInts.set(1, inputSequence.get(start + 1));
}
if(count > max_length) {
max_length = count;
}
}
return max_length;
}
public static void main(String[] args) {
List<Integer> input = new LinkedList<Integer>(Arrays.asList(53,800,0,0,0,356,8988,1,1));
System.out.println(maxCommonArraySlice(input));
}
I think this would work:
public int solution(int[] arr) {
int lastSeen = -1;
int secondLastSeen = -1;
int lbs = 0;
int tempCount = 0;
int lastSeenNumberRepeatedCount = 0;
for (int current : arr) {
if (current == lastSeen || current == secondLastSeen) {
tempCount ++;
} else {
// if the current number is not in our read list it means new series has started, tempCounter value in this case will be
// how many times lastSeen number repeated before this new number encountered + 1 for current number.
tempCount = lastSeenNumberRepeatedCount + 1;
}
if (current == lastSeen) {
lastSeenNumberRepeatedCount++;
} else {
lastSeenNumberRepeatedCount = 1;
secondLastSeen = lastSeen;
lastSeen = current;
}
lbs = Math.max(tempCount, lbs);
}
return lbs;
}
Reference
This is a python solution, as per requested by OP
def solution(arr):
if (len(arr) <= 2): print arr
lres = 0
rres = 0
l = 0
r = 1
last = arr[1]
prev = arr[0]
while(r <= len(arr)-1):
if prev != last:
if arr[r] == prev:
prev = last
last = arr[r]
elif arr[r] != last:
l = r-1
while(arr[l-1] == last):
l -= 1
last = arr[r]
prev = arr[r-1]
else:
if arr[r] != prev:
last = arr[r]
if r - l > rres-lres:
rres = r
lres = l
r += 1
print arr[lres:rres+1]
For current segment let's say that last is the last value added and prev is the second distinct value in the segment. (initially they might be equal).
Let's keep to pointers l and r to left and right ends of the current segment with at most two distinct elements. And let's say we consider element arr[r].
If current segment [l,r-1] contains only one distinct element, we can safely add arr[r], with possibly updating last and prev.
Now if arr[r] equals to last, then we don't need to do anything. If arr[r] equals to prev, we need to swap prev and last. If it equals to neither of those two, we need to update l left pointer, by tracing back from r-1 until we find an element which is not equal to last, then update last and prev.
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);
}
}
}