Maximum distance between two different element in an array - java

I have a problem where I need to find the maximum distance between two different elements in an array.
For example: given an array 4,6,2,2,6,6,4 , the method should return 5 as the max distance.
I am able to solve the problem using two for loops but it is not an optimized solution. Am trying to optimize it by doing it in a single for loop.
here is my current solution:
int [] A = {4,6,2,2,6,6,4};
int N = A.length;
int result = 0;
for (int i = 0; i < N; i++){
for (int j = i; j < N; j++) {
if(A[i] != A[j]){
result = Math.max(result, j - i);
}
}
}
// tried below code but it is not efficient
// for (int i = 0; i < N; i++){
//
// if(A[N-1] != A[i]){
// result = Math.max(result, N-1-i);
// }
// }
System.out.println(result);
How to make this better in terms of time complexity?

Simple (not nested) loop is enough, but two cases should be taken into
account: either the best result is
4,6,2,2,6,6,4
^ ^ - moving first
or
4,6,2,2,6,6,4
^ ^ - moving last
for instance: [4, 2, 4, 4, 4] moving first brings the answer, when in case of [4, 4, 4, 2, 4] moving last should be used.
int first = 0;
int last = A.length - 1;
// 1st case: moving "first"
while (first < last) {
if (A[first] == A[last])
first++;
else
break;
}
int diff1 = last - first;
first = 0;
last = A.length - 1;
// 2nd case: moving "last"
while (first < last) {
if (A[first] == A[last])
last--;
else
break;
}
int diff2 = last - first;
// result is the max between two cases
int result = diff1 > diff2
? diff1
: diff2;
So we have O(N) time complexity.
Edit: Let's proof that at least one of the indexes is either 0 or length - 1. Let's do it by contradiction. Suppose we have a solution like
a, b, c, .... d, e, f, g
^ ..... ^ <- solution indexes (no borders)
Items to the left of c must be d, otherwise we can take a or b indexes and have an improved solution. Items to right of d must be c or we can once again push last index to the right and have a better solution. So we have
d, d, c .... d, c, c, c
^ .... ^ <- solution indexes
Now, since d <> c (c..d is a solution) we can improve the solution into
d, d, c .... d, c, c, c
^ .... ^ <- solution indexes
^ .... ^ <- better solution
We have a contradiction (the supposed solution is not one - we have a better choice) and that's why at least one index must be 0 or length - 1.
Now we have 2 scenarions to test:
a, b, ..... y, z
^ ...... ^ <- moving first
^ ...... ^ <- moving last
We can combine both conditions into if and have just one loop:
int result = 0;
for (int i = 0; i < A.length; ++i)
if (A[i] != A[A.length - 1] || A[0] != A[A.length - 1 - i]) {
result = A.length - i - 1;
break;
}

This can be done in a single loop
Consider this.
The maximum difference between from a index i can be either between start element and i or i and the last element
int main() {
vector<int> v {4, 6, 2, 2, 6, 6, 4};
int start = 0, end = v.size() -1;
int result = 0;
for(int i=0; i< v.size(); ++i)
{
if(v[i] != v[start])
{
result = max(result, i);
}
if(v[i] != v[end])
{
result = max(result, end - i);
}
}
return result;
}
The reason we are able to achieve a O(N) algorithm is because
Consider v = [4, 4, 2, 3, 4, 4]
At index i = 0 we check if we can find the maximum possible distance i.e with the last element but since they are same we can't consider it.
At i = 0 for this array the maximum possible answer would have been 5.
[4, 4, 2, 3, 4, 4]
^
At i = 1 we again check both ends of the array still the same so we move on.
The real savings come here that we do not have to check for every other entry
keeping the start at i = 0
So, at i = 2, we find that the maximum can be obtained with the end of the array
[4, 4, 2, 3, 4, 4]
^ ^ ^
start i end
which is the same as keeping the start constant and keeping a runner loop.

Related

Counting triplets with smaller sum

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!

Maximize the number of Elements in the Array divisible by M

I'm working on the following task.
Given an array of n integers and two integer numbers m and k.
You can add any positive integer to any element of the array such that
the total value does not exceed k.
The task is to maximize the
multiples of m in the resultant array.
Consider the following example.
Input:
n = 5, m = 2, k = 2, arr[] = [1, 2, 3, 4, 5]
Let's add 1 to the element arr[0] and 1 to arr[2] then the final array would be:
[2, 2, 4, 4, 5]
Now there are four (4) elements which are multiples of m (2).
I am not getting correct output.
My code:
public class Main {
public static void main(String[] args) {
int n = 5;
int m = 4;
int k = 3;
int count = 0;
int[] arr = {17, 8, 9, 1, 4};
for (int i = 0; i < n; i++) {
for (int j = 0; j <= k; j++) {
// check initial
if (arr[i] % m == 0) {
break;
}
// add
arr[i] = arr[i] + j;
// check again
if (arr[i] % m == 0) {
count++;
break;
}
}
}
System.out.println("Final Array : " + Arrays.toString(arr));
System.out.println("Count : " + count);
}
}
This task boils down to a well-known Dynamic programming algorithm called Knapsack problem after a couple of simple manipulations with the given array.
This approach doesn't require sorting and would be advantages when k is much smaller n.
We can address the problem in the following steps:
Iterate over the given array and count all the numbers that are already divisible by m (this number is stored in the variable count in the code below).
While iterating, for every element of the array calculate the difference between m and remainder from the division of this element by m. Which would be equal to m - currentElement % m. If the difference is smaller or equal to k (it can cave this difference) it should be added to the list (differences in the code below) and also accumulated in a variable which is meant to store the total difference (totalDiff). All the elements which produce difference that exceeds k would be omitted.
If the total difference is less than or equal to k - we are done, the return value would be equal to the number of elements divisible by m plus the size of the list of differences.
Otherwise, we need to apply the logic of the Knapsack problem to the list of differences.
The idea behind the method getBestCount() (which is an implementation Knapsack problem) boils down to generating the "2D" array (a nested array of length equal to the size of the list of differences +1, in which every inner array having the length of k+1) and populating it with maximum values that could be achieved for various states of the Knapsack.
Each element of this array would represent the maximum total number of elements which can be adjusted to make them divisible by m for the various sizes of the Knapsack, i.e. number of items available from the list of differences, and different number of k (in the range from 0 to k inclusive).
The best way to understand how the algorithm works is to draw a table on a piece of paper and fill it with numbers manually (follow the comments in the code, some intermediate variables were introduced only for the purpose of making it easier to grasp, and also see the Wiki article linked above).
For instance, if the given array is [1, 8, 3, 9, 5], k=3 and m=3. We can see 2 elements divisible by m - 3 and 9. Numbers 1, 8, 5 would give the following list of differences [2, 1, 1]. Applying the logic of the Knapsack algorithm, we should get the following table:
[0, 0, 0, 0]
[0, 0, 1, 1]
[0, 1, 1, 2]
[0, 1, 2, 2]
We are interested in the value right most column of the last row, which is 2 plus 2 (number of elements divisible by 3) would give us 4.
Note: that code provided below can dial only with positive numbers. I don't want to shift the focus from the algorithm to such minor details. If OP or reader of the post are interested in making the code capable to work with negative number as well, I'm living the task of adjusting the code for them as an exercise. Hint: only a small change in the countMultiplesOfM() required for that purpose.
That how it might be implemented:
public static int countMultiplesOfM(int[] arr, int k, int m) {
List<Integer> differences = new ArrayList<>();
int count = 0;
long totalDiff = 0; // counter for the early kill - case when `k >= totalDiff`
for (int next : arr) {
if (next % m == 0)
count++; // number is already divisible by `m` we can increment the count and from that moment we are no longer interested in it
else if (m - next % m <= k) {
differences.add(m - next % m);
totalDiff += m - next % m;
}
}
if (totalDiff <= k) { // early kill - `k` is large enough to adjust all numbers in the `differences` list
return count + differences.size();
}
return count + getBestCount(differences, k); // fire the rest logic
}
// Knapsack Algorithm implementation
public static int getBestCount(List<Integer> differences, int knapsackSize) {
int[][] tab = new int[differences.size() + 1][knapsackSize + 1];
for (int numItemAvailable = 1; numItemAvailable < tab.length; numItemAvailable++) {
int next = differences.get(numItemAvailable - 1); // next available item which we're trying to place to knapsack to Maximize the current total
for (int size = 1; size < tab[numItemAvailable].length; size++) {
int prevColMax = tab[numItemAvailable][size - 1]; // maximum result for the current size - 1 in the current row of the table
int prevRowMax = tab[numItemAvailable - 1][size]; // previous maximum result for the current knapsack's size
if (next <= size) { // if it's possible to fit the next item in the knapsack
int prevRowMaxWithRoomForNewItem = tab[numItemAvailable - 1][size - next] + 1; // maximum result from the previous row for the size = `current size - next` (i.e. the closest knapsack size which guarantees that there would be a space for the new item)
tab[numItemAvailable][size] = Math.max(prevColMax, prevRowMaxWithRoomForNewItem);
} else {
tab[numItemAvailable][size] = Math.max(prevRowMax, prevColMax); // either a value in the previous row or a value in the previous column of the current row
}
}
}
return tab[differences.size()][knapsackSize];
}
main()
public static void main(String[] args) {
System.out.println(countMultiplesOfM(new int[]{17, 8, 9, 1, 4}, 3, 4));
System.out.println(countMultiplesOfM(new int[]{1, 2, 3, 4, 5}, 2, 2));
System.out.println(countMultiplesOfM(new int[]{1, 8, 3, 9, 5}, 3, 3));
}
Output:
3 // input array [17, 8, 9, 1, 4], m = 4, k = 3
4 // input array [1, 2, 3, 4, 5], m = 2, k = 2
4 // input array [1, 8, 3, 9, 5], m = 3, k = 3
A link to Online Demo
You must change 2 line in your code :
if(arr[i]%m==0)
{
count++; // add this line
break;
}
// add
arr[i]=arr[i]+1; // change j to 1
// check again
if(arr[i]%m==0)
{
count++;
break;
}
The first is because the number itself is divisible.
and The second is because you add a number to it each time.That is wrong.
for example chenge your arr to :
int[] arr ={17,8,10,2,4};
your output is :
Final Array : [20, 8, 16, 8, 4]
and That is wrong because 16-10=6 and is bigger than k=3.
I believe the problem is that you aren't processing the values in ascending order of the amount by which to adjust.
To solve this I started by using a stream to preprocess the array. This could be done using other methods.
map the values to the amount to make each one, when added, divisible by m.
filter out those that equal to m' (already divisible by m`)
sort in ascending order.
Once that is done. Intialize max to the difference between the original array length and the processed length. This is the number already divisible by m.
As the list is iterated
check to see if k > amount needed. If so, subtract from k and increment max
otherwise break out of the loop (because of the sort, no value remaining can be less than k)
public static int maxDivisors(int m, int k, int[] arr) {
int[] need = Arrays.stream(arr).map(v -> m - v % m)
.filter(v -> v != m).sorted().toArray();
int max = arr.length - need.length;
for (int val : need) {
if (k >= val) {
k -= val;
max++;
} else {
break;
}
}
return max;
}
int m = 4;
int k = 3;
int[] arr ={17,8,9,1,4};
int count = maxDivisors(m, k, arr);
System.out.println(count);
prints
3

Array left rotation in Java

Given an array of integers and a number, I need to perform left rotations on the array and return the updated array to be printed as a single line of space-separated integers.
I pass 7/9 checks, but some with large arrays fail because of time-out.
The time has to be <= 4 sec.
static int[] rotLeft(int[] a, int d) {
int x = 0;
while (x != d) {
int first = a[0];
int last = a[a.length - 1];
for (int i = 0; i < a.length - 1; i++) {
a[i] = a[i + 1];
if (i == a.length - 2)
a[a.length - 2] = last;
a[a.length - 1] = first;
}
x++;
}
return a;
}
you're rotating only one position at a time, it is very slow, it is better to shift elements to appropriate places, for example:
static int[] rotLeft(int[] a, int d) {
if (d == 0 || a == null || a.length == 0) {
return a;
}
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
b[i] = a[(i + d) % a.length];
}
return b;
}
There are two things you could apply to this problem to improve the runtime.
Ensure that d is less than a.length. If d is greater than a.length, then you are rotating elements past their original position and wasting cycles. An easy way to achieve this is with the modulus assignment operator (i.e., d %= a.length, which is equivalent to d = d % a.length).
Elements should be shifted by the whole distance we are rotating, rather than shifting by one space each time. This allows us to perform the entire operation is 1 action, instead of in d action(s).
Applying these two principles would give us the following code:
static int[] rotLeft(int[] a, int d) {
if (d < 0) {
d = a.length - (-d % a.length);
}
d %= a.length;
if (d == 0) {
return a;
}
int first = a[0];
int i = 0;
int position = 0;
while (i < a.length) {
a[position] = a[(position + d) % a.length];
position = (position + d) % a.length;
i++;
}
a[a.length - d] = first;
return a;
}
You make multiple passes, each time rotating by one place, which makes your program slow.
There are at least 3 approaches to improve your program:
allocate a new array and put elements in appropriate locations, instead of rotating in place
use a buffer to store d elements while rotating others in place
use a juggling algorithm https://www.google.com/amp/s/www.geeksforgeeks.org/array-rotation/amp/
The third option performs rotation in place.
It may be worthwhile to microbenchmark all 3 to compare the speed for different input sizes
Of course you can repeat the rotation d times as you did in your sample code. But much faster would be if you would calculate the shift and do it in one go:
import static java.lang.System.*;
static int[] rotLeft( int[] a, int d )
{
var len = a.length;
var shift = d % len;
var buffer = new int[len];
arraycopy( a, shift, buffer, 0, len - shift );
arraycopy( a, 0, buffer, len - shift, shift );
arraycopy( buffer, 0, a, 0, len );
return a;
}
Of course, instead of System.arraycopy() you can use a for-loop. If you are not forced to return a, you can omit the third call to arraycopy() and return buffer instead; this would leave the original array unchanged, too.
To output the array, try this:
var joiner = new StringJoiner( " " );
for( var v : a ) joiner.add( Integer.toString( v ) );
System.out.println( joiner.toString() );
For better performance, you should use the built-in array copy methods.
If you have to update the existing array, like your code is doing, I'd recommend doing it like this:
static int[] rotLeft(int[] a, int d) {
if (a == null || a.length <= 1)
return a; // nothing to rotate
int shift = (d % a.length + a.length) % a.length; // normalize d
if (shift == 0)
return a; // no or full rotation(s)
int[] t = Arrays.copyOfRange(a, 0, shift);
System.arraycopy(a, shift, a, 0, a.length - shift);
System.arraycopy(t, 0, a, a.length - shift, shift);
return a;
}
If the returned array must be different, like this other answers do, I'd do it like this:
static int[] rotLeft(int[] a, int d) {
if (a == null || a.length <= 1)
return Arrays.copyOf(a, a.length); // nothing to rotate
int shift = (d % a.length + a.length) % a.length; // normalize d
if (shift == 0)
return Arrays.copyOf(a, a.length); // no or full rotation(s)
int[] t = new int[a.length];
System.arraycopy(a, shift, t, 0, a.length - shift);
System.arraycopy(a, 0, t, a.length - shift, shift);
return t;
}
Both of the above solution allow d to exceed the size of the array, i.e. do more than a full rotation, and to use negative values, i.e. rotate right instead of left.
Test
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 1)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 3)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 5)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 7)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, -7)));
Output
[2, 3, 4, 5, 1]
[4, 5, 1, 2, 3]
[1, 2, 3, 4, 5]
[3, 4, 5, 1, 2]
[4, 5, 1, 2, 3]
You don't have to do the rotations one by one. If you rotate by d, the element at index i moves to index i - d when i >= d, and into index N + i - d when i < d. Makes sense?
int[] result = new int[a.length]
for (int i = 0; i < a.length; i++) {
if (i < d) {
result[a.length + i - d] = a[i];
} else {
result[i - d] = a[i];
}
}
return result;
To handle the case where d >= a.length, you can add d = d % a.length as a pre-processing step.

Maximum Arithmetic sequence of two different array

Given two arrays of ints, a and b, try to create an arithmetic sequence by adding ints from b into a. Return the maximum length of a or -1 if there does not exist an arithmetic sequence e.g. a = [2, 4, 8], b = [1, 6, 10, 12] -> a = [2, 4, 6, 8, 10, 12] -> return 6
I tried creating a new array and merging both a and b and counting the longest subsequence but the count could remove elements from a which should not be touched
static int maxSeq(int[] arr1, int[] arr2){
if(arr1.length ==0)return 0;
int n =arr1.length, m = arr2.length;
int[] arr = new int[n+m];
System.arraycopy(arr1,0,arr,0,n);
System.arraycopy(arr2,0,arr,n,m);
Arrays.sort(arr);
int result =0;
Map<Integer,Integer>[]d = new HashMap[n+m];
for(int i =0; i < arr.length;i++){
d[i] = new HashMap<Integer, Integer>();
}
for(int i =1; i < arr.length; ++i){
for(int j = 0; j<i;++j ){
int diff = arr[i]-arr[j];
int len =2;
if(d[j].containsKey(diff)){
len = d[j].get(diff) +1;
}
d[i].put(diff,len);
result = Math.max(result,d[i].get(diff));
}
}
return result;
}
a = [2, 4, 8], b = [1, 6, 10, 12] -> a = [2, 4, 6, 8, 10, 12] -> return 6
int[] a = {5,7,13,14}, b = {9,11,15}; return -1 not 6
I think you should try to fix your code.
if(d[j].containsKey(diff)){ len = d[j].get(diff) +1; }
Here you are looking for differences in a map of some index j, and there should be only one map of key value paires, not array of maps.
The key here is to fill in array A with numbers from array B so A become an arithmetic sequence.
Solution:
First find the minimum gap between 2 consequence number in A
With the given "gap", try to see if an arithmetic sequence can be build by looping through the 2 arrays, and find out if numbers in B can fill in array A so A become arithmetic with step = "gap". Take count of the length if success.
If it can be found, try to see if smaller gap can build longer arithmetic sequence by looping through all the divisor of the original "gap" as the new "gap" and test again. (example: A = [ 1,5], B= [3,7,9] => Previous step see that we can build arithmetic sequence [1,5,9], but the final answer should be [1,3,5,7,9].
I'd like to share my solution (probably is not optimized and I did not wrote many tests, but it worked on your two sample tests):
Idea:
Notice the common difference d of arithmetic sequence is upperbounded by min(a[i] - a[i-1]), otherwise we won't be able to visit all elements in a
We iterate on common difference d to check the length of each potential list, and find the max length
Complete code in Python:
(Suppose a, b are both sorted)
def max_arithmetic_length(a, b):
min_diff = float('inf') # common difference d is upper bounded by min_diff
for i in range(1, len(a)):
min_diff = min(min_diff, a[i] - a[i-1])
d_a = {x : True for x in a}
d_b = {x : True for x in b}
max_cnt = 0
for d in range(1, min_diff + 1):
skip_current_d = False # a switch to skip outer loop
for x in a:
if (x - a[0]) % d != 0: # must exist: a[i] - a[0] = kd
skip_current_d = True
break
if skip_current_d:
continue
cur = a[0]
cnt = 0
visited = {}
while cur in d_a or cur in d_b:
cnt += 1
visited[cur] = True
cur += d
if a[-1] not in visited: # if the last element in a is visited, then every element in a is visited
continue
# check those smaller than a[0] (may only exist in b)
cur = a[0] - d
while cur in b:
cnt += 1
cur -= d
max_cnt = max(cnt, max_cnt)
return max_cnt if max_cnt else -1
a = [2, 4, 8]
b = [1, 6, 10, 12]
print(max_arithmetic_length(a,b)) # return 6
a = [5,7,13,14]
b = [9,11,15]
print(max_arithmetic_length(a,b)) # return -1

how can you find the length of the longest subset (powerset) with sum equal to k with least time complexity?

Given an array of integers, I'm trying to find the longest subset (powerset) with sum equal to k using the lease possible time complexity.
e.g. if inputArr= [1, 2, 8, 1, 1, 7] and k= 10, then the output should be 4 since the longest subset with sum equals to 10 is [1, 1, 1, 7].
Edit: I might've forgotten an important detail; the elements of the array are all positive and non-zero.
I used this algorithm that I found on geeksforgeeks:
https://www.geeksforgeeks.org/finding-all-subsets-of-a-given-set-in-java/
The code works fine, but the only problem that I have is with the execution time. I am supposed to submit this online, and when I submit it the execution terminates due to timeout.
int maxSubLength=0;
for (int i = 1; i < (1<<n); i++) //n is the length of inputArr
{
int sum=0, length=0;
for (int j = 0; j < n; j++)
if ((i & (1 << j)) > 0)
{
sum+=inputArr[j];
length++;
if (sum>k)
break;
}
if (sum==k)
maxSubLength=Math.max(maxSubLength, length);
}
Is there any faster algorithm? I tried a recursive one and it didn't help.
We can solve this with dynamic programming in O(n*k) time and O(k) space. JavaScript code:
function f(A, K){
let m = new Array(K + 1).fill(0)
for (let a of A){
for (let k=K; k>=a; k--)
if (m[k - a])
m[k] = Math.max(m[k], 1 + m[k - a])
m[a] = Math.max(m[a], 1)
}
return m[K]
}
var A = [1, 2, 8, 1, 1, 7]
var K = 10
console.log(f(A, K))

Categories