I am getting error stating Terminated due to timeout for larger inputs when using ArrayList, for smaller one it works fine.
I watched solutions where they were using PREFIX SUM ALGORITHM and 2-dimension array as parameter. Can we not use ArrayList as parameter instead of array?
Here is the question ---
Starting with a 1-indexed array of zeros and a list of operations, for each operation add a value to each of the array element between two given indices, inclusive. Once all operations have been performed, return the maximum value in your array.
For example, the length of your array of zeros . Your list of queries is as follows:
a b k
1 5 3
4 8 7
6 9 1
Add the values of between the indices and inclusive:
index -> 1 2 3 4 5 6 7 8 9 10
[0,0,0, 0, 0,0,0,0,0, 0]
[3,3,3, 3, 3,0,0,0,0, 0]
[3,3,3,10,10,7,7,7,0, 0]
[3,3,3,10,10,8,8,8,1, 0]
The largest value is returned after all operations are performed.
Here the output will be 10;
My code is
public static long arrayManipulation(int n, List<List<Integer>> queries) {
List<Integer> arr = new ArrayList<Integer>(Collections.nCopies(n+1, 0));
//PREFIX SUM
for(int i = 0; i<queries.size(); i++){
int a = queries.get(i).get(0)-1;
int b = queries.get(i).get(1);
int k = queries.get(i).get(2);
arr.set(a, arr.get(a)+k);
arr.set(b, arr.get(b)-k);
}
long max=0;
for(int i = 1; i < arr.size(); i++)
{
arr.set(i, arr.get(i)+arr.get(i-1));
if(arr.get(i)>max)
{
max=arr.get(i);
}
}
Collections.sort(arr);
return arr.get(n);
}
Related
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
I have an array of numbers and another number K.
My task is to reduce the number of distinct elements in the array. For that, I can update the array several times. For updating the array, I have to follow these steps:
Select an element at index i and add that element by K, and reduce all other remaining elements by K.
For updating an array I can select the same index several times.
Example:
K = 1
Array: [3,1,3]
Answer: 3
I am picking index = 1, as [3-1, 1+1, 3-1] = [2,2,2] so we have number 2 that appears 3 times so this element occurs maximum number of times. So answer is 3.
Another example:
K = 1
Array: [1,2,2]
Answer: 2
It's not possible to make all elements same, so we have number 2 that appears 2 times, so answer is 2.
Array size can be [1, 1000], and the value of K and elements in array is in range [0, 1000]
Here is my code that I tried, my my approach is not correct.
public static int process(int K, int[] A) {
Map<Integer, Integer> map = new TreeMap<>();
for (int key : A) {
map.put(key, map.getOrDefault(key, 0) + 1);
}
int result = 0;
boolean flag = false;
int last = -1, cur = -1;
for (int key : map.keySet()) {
if (flag == false) {
flag = true;
last = key;
continue;
}
cur = key;
int a = map.get(last), b = map.get(cur);
if (Math.abs(last - cur) > K) {
result += a + b;
} else {
result += Math.max(a, b);
}
}
last = cur;
return result;
}
When looking at the examples with K = 1, it is clear that the answer
depends on the parity of the elements. Only elements with same parity can be set to the same level,
and all elements with same parity can be joined.
For example:
[2 4 6] -> [1 5 5] -> [2 4 4] -> [3 3 3]
[1 2 2] -> [2 1 1] ... no progress
With K = 1, we have to consider value modulo 2, i.e. modulo 2*K.
When K is different of one, for example K = 2, two numbers can be joined only there are separated by a distance multiple of 4, i.e. of 2*K.
[2 6 6] -> [4 4 4]
For K different from 1, instead of creating buckets for numbers with same parity,
we just create buckets according to value modulo 2K.
We just have to pay attention to use the modulo and not the remainder, the values are different for negative values.
Then the answer if simply the highest size of a bucket.
Output:
K = 1 Array : 3 1 3 -> 3
K = 1 Array : 1 2 2 -> 2
K = 1 Array : 2 3 4 7 4 9 11 -> 4
K = 1 Array : -3 -1 2 3 -> 3
K = 3 Array : -7 -1 0 1 2 4 5 -> 3
Here is a simple code in C++ to illustrate the algorithm.
In this code, the value val_modulo modulo 2K of each element is calculated.
Then, the orresponding counter is increased
Bucket[val_modulo] = Bucket[val_modulo] + 1
At the end, the highest value corresponds to the number of repetitions of the most repeated final value.
We may note that the number of non empty bucket corrresponds to the number of different
final values (not used in this code).
#include <iostream>
#include <vector>
#include <string>
#include <map>
void print (const std::vector<int> &A, const std::string &after = "\n", const std::string &before = "") {
std::cout << before;
for (int x: A) {
std::cout << x << " ";
}
std::cout << after;
}
int Modulo (int n, int mod) {
int ans = n % mod;
if (ans < 0) ans += mod;
return ans;
}
int max_equal(int K, std::vector<int> A) {
K = std::abs(K); // useful befoe taking the modulo
std::map<int, int> Buckets;
int nmax = 0;
int mod = 2*K;
for (int x: A) {
int val_modulo = Modulo (x, mod); // and not x*mod, as x can be negative
Buckets[val_modulo]++;
}
for (auto x: Buckets) {
if (x.second > nmax) {
nmax = x.second;
}
}
return nmax;
}
int main() {
std::vector<std::vector<int>> examples = {
{3, 1, 3},
{1, 2, 2},
{2, 3, 4, 7, 4, 9, 11},
{-3, -1, 2, 3},
{-7, -1, 0, 1, 2, 4, 5}
};
std::vector<int> tab_K = {1, 1, 1, 1, 3};
for (int i = 0; i < examples.size(); ++i) {
std::cout << "K = " << tab_K[i] << " Array : ";
print (examples[i], " -> ");
auto ans = max_equal (tab_K[i], examples[i]);
std::cout << ans << "\n";
}
return 0;
}
The problem is conceptual, and translating it in somewhat computing code.
Let's look:
We pick a number (by index, which is irrelevant), and for all the occurrences we add K. All others we subtract K And then the number of same occurrences must be maximal.
The same occurrences can only grow when the picked number + K is equal to another number - K.
The data structure:
A map with the array numbers as key, and mapped to frequency (how often the number occurs in the array).
So:
pickedNumber.value + K = otherNumber.value - K
=> otherNumber.value = pickedNumber.value + 2*K
Note that as there is only one single otherNumber, derived from the pickedNumber.
(It might occur more than once.)
And we want maximal:
pickedNumber.frequency + otherNumber.frequency maximal.
Though map is not really needed, a sorted array would do too, let's do a map:
The algorithm:
Kept simple.
int[] numbers = {3, 1, 3};
int index = pickedIndexOfBestSolution(numbers, 1);
System.out.println("Index: " + index);
int pickedIndexOfBestSolution(int[] numbers, int k) {
Map<Integer, Long> frequencyTable = IntStream.of(numbers)
.boxed()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
int bestNumber = frequencyTable.entrySet().stream()
.sorted(Comparator.comparingLong(e -> -e.getValue()
- frequencyTable.getOrDefault(e.getKey() + 2*k, 0L)))
.findFirst()
.map(e -> e.getKey())
.orElseThrow();
int index = -1;
while (numbers[++index] != bestNumber) {
}
return index;
}
The frequency table I filled using an IntStream and groupingBy (just as SQL).
As counting is done with long, I just kept that.
To find the max I counted the new occurrence count trying to add the "other" number's frequency too; 0 when no other number.
Instead of using .reverse() to reverse the comparison (largest, max, first), I took the negative value, which to me seems more calculatory.
Notice that a Stream with findFirst to find the max is probably optimal too: no need that the stream creates an intermediate list.
For the index I used brute force (while loop), a kind of indexOf.
Notice if there is no other number, it returns the index of a number with the most occurrences. Which is fine.
In short:
You see the different approach. Actually simpler, and more solid. In fact applying
some (minor) intelligence first. Trying to nail down the problem first.
I have an array of numbers, now I want to find all the consecutive subarray sums whose value matches with less than or equal to k. I want to return the largest subarray size.
This is my program:
public static int process(List<Integer> arr, int k) {
int size = 0;
for (int i = 0; i < arr.size(); i++) {
int sum = 0;
for (int j = i; j < arr.size(); j++) {
sum += arr.get(j);
if (sum <= k) {
size = Math.max(size, j - i + 1);
}
}
}
return size;
}
constraints:
arr size is between 1 to 100000
array elements are between 1 to 100
k is between 1 to 1000000
Explanation:
Arrays.asList(2, 3, 5, 1, 1, 2, 1), 7
arr = 2, 3, 5, 1, 1, 2, 1
k= 7
possible sub arrays:
[2], [3], [5], [1], [1], [2], [1]
[2,3], [5,1], [1,1], [1,2], [2,1]
[5,1,1], [1,1,2], [1,2,1]
[1,1,2,1]
Maximum sub array is [1,1,2,1] = its length is 4. So program should return 4.
I got this task in a competitive exam last week, when I used this code it has passed only 50% test cases. It failed for some hidden test cases saying wrong output, and some test cases saying time out.
What is the issue with my code?
Update:
Modified my code little bit. And added a sample example.
Nested loops means that performance is O(n2). You need to re-think the algorithm.
Below is an O(n) solution, which I will show by example. Writing the code is still your challenge.
What we need is a way to know the sum of values before a particular index. With that we can calculate sumRange(i, j) = sumBefore(j) - sumBefore(i).
Since we're looking for sumRange(i, j) = k, we need to check if we have a sumBefore(i) = sumBefore(j) - k. If we do, we have a candidate range with size = j - i.
So, iterate the values and calculate the accumulated sum. Build a Map of accSum to indexAfter the value leading to that accumulated sum.
Say the array is [1, 6, 5, 3, 2, 8, 4, 2, 7, 1] and k = 13:
Index: 0 1 2 3 4 5 6 7 8 9
Value: 1 6 5 3 2 8 4 2 7 1
accSum: 0 1 7 12 15 17 25 29 31 38 39 sumBefore
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
indexAfter: 0 1 2 3 4 5 6 7 8 9 10 index
Adding the dummy 0 → 0 mapping just simplifies the logic of your code.
As you iterate, you have the accumulated sum up to now, inclusive, i.e. sumBefore(i + 1), so look to see if we have a range, i.e. sumBefore(x) = sumBefore(i + 1) - k = accSum - k, so look in the map for accSum - k, and if found, the value is x, meaning we have a candidate range of x, i+1.
I hope that all made sense.
UPDATE
The question was changed to look for sums <= k, not just sums exactly equal to k.
This is easily done with the logic above by changing the Map to a TreeMap, or more specifically a NavigableMap, and replace the get() call with a ceilingEntry() call:
Returns a key-value mapping associated with the least key greater than or equal to the given key, or null if there is no such key.
If the returned key (sum) is greater than the parameter, the result is a subarray sum that is less than k.
For example I have array with length n=3:
for(int i = 0; i < n; i++) {
array[i] = i;
}
So the cases should be:
1. 0
2. 1
3. 2
4. 0 1
5. 0 2
6. 1 2
7. 0 1 2
So the number of cases should be 7 for n = 3.
In my code:
int n = 3;
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = i;
}
int sum = 0;
for (int i = 0; i < n; i++) {
System.out.println(array[i] + " ");
sum++;
for (int j = i; j < n; j++) {
System.out.print(array[j] + " ");
}
System.out.println();
sum++;
}
System.out.println("sum = " + sum);
Output is:
0
0 1 2
1
1 2
2
2
sum = 6
The number 2 is two times so it is wrong and sum is actually = 5. And I don't get cases
4. 0 1
and
5. 0 2
How to count all possible cases?
Sets, not arrays
The first important observance is that you are not using fixed length arrays here but sets of different lengths.
Take a look at your example. You allow
0
1
2
0, 1
0, 2
1, 2
which are not all of size 3.
Also you don't differentiate between
0, 1
1, 0
so order doesn't matter, like in sets.
Power set
That's why you're actually describing power sets here. For the example set {0, 1, 2} its power set is defined as
P({0, 1, 2}) = {
{}, // empty set
{0},
{1},
{2},
{0, 1},
{0, 2},
{1, 2},
{0, 1, 2}
}
Fortunately there exists an easy closed formula for their size. If n is the size of the input set the size of the power set is
2^n
But they also count the empty set, so you will need to -1 if you don't want that:
2^n - 1
Solution
Thus in Java you could write
int Set<Integer> input = ...
int size = (int) Math.pow(2, input.size()) - 1;
and that's all, you don't need to build the contents manually.
But if you're curious and want to build them, take a look at questions like Obtaining a powerset of a set in Java. It's an implementation of the recursive formula shown at Wikipedia.
So, totally inefficient but also working:
int Set<Integer> input = ...
// Build the power-set using the method from linked question
Set<Set<Integer>> power = powerSet(input);
int size = power.size() - 1;
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Right now I'm trying to write a function that takes an array and an integer n, and gives a list of each size n combination (so a list of int arrays). I am able to write it using n nested loops, but this only works for a specific size of subset. I can't figure out how to generalize it to work for any size of combination. I think I need to use recursion?
This is the code for all combinations of 3 elements, and I need an algorithm for any number of elements.
import java.util.List;
import java.util.ArrayList;
public class combinatorics{
public static void main(String[] args) {
List<int[]> list = new ArrayList<int[]>();
int[] arr = {1,2,3,4,5};
combinations3(arr,list);
listToString(list);
}
static void combinations3(int[] arr, List<int[]> list){
for(int i = 0; i<arr.length-2; i++)
for(int j = i+1; j<arr.length-1; j++)
for(int k = j+1; k<arr.length; k++)
list.add(new int[]{arr[i],arr[j],arr[k]});
}
private static void listToString(List<int[]> list){
for(int i = 0; i<list.size(); i++){ //iterate through list
for(int j : list.get(i)){ //iterate through array
System.out.printf("%d ",j);
}
System.out.print("\n");
}
}
}
This is a well-studied problem of generating all k-subsets, or k-combinations, which can be easily done without recursion.
The idea is to have array of size k keeping sequence of indices of elements from the input array (which are numbers from 0 to n - 1) in increasing order. (Subset then can be created by taking items by these indices from the initial array.) So we need to generate all such index sequences.
First index sequence will be [0, 1, 2, ... , k - 1], on the second step it switches to [0, 1, 2,..., k], then to [0, 1, 2, ... k + 1] and so on. The last possible sequence will be [n - k, n - k + 1, ..., n - 1].
On each step, algorithm looks for the closest to the end item which can be incremented, increments it and fills up items right to that item.
To illustrate, consider n = 7 and k = 3. First index sequence is [0, 1, 2], then [0, 1, 3] and so on... At some point we have [0, 5, 6]:
[0, 5, 6] <-- scan from the end: "6" cannot be incremented, "5" also, but "0" can be
[1, ?, ?] <-- "0" -> "1"
[1, 2, 3] <-- fill up remaining elements
next iteration:
[1, 2, 3] <-- "3" can be incremented
[1, 2, 4] <-- "3" -> "4"
Thus, [0, 5, 6] is followed by [1, 2, 3], then goes [1, 2, 4] etc.
Code:
int[] input = {10, 20, 30, 40, 50}; // input array
int k = 3; // sequence length
List<int[]> subsets = new ArrayList<>();
int[] s = new int[k]; // here we'll keep indices
// pointing to elements in input array
if (k <= input.length) {
// first index sequence: 0, 1, 2, ...
for (int i = 0; (s[i] = i) < k - 1; i++);
subsets.add(getSubset(input, s));
for(;;) {
int i;
// find position of item that can be incremented
for (i = k - 1; i >= 0 && s[i] == input.length - k + i; i--);
if (i < 0) {
break;
}
s[i]++; // increment this item
for (++i; i < k; i++) { // fill up remaining items
s[i] = s[i - 1] + 1;
}
subsets.add(getSubset(input, s));
}
}
// generate actual subset by index sequence
int[] getSubset(int[] input, int[] subset) {
int[] result = new int[subset.length];
for (int i = 0; i < subset.length; i++)
result[i] = input[subset[i]];
return result;
}
If I understood your problem correctly, this article seems to point to what you're trying to do.
To quote from the article:
Method 1 (Fix Elements and Recur)
We create a temporary array ‘data[]’ which stores all outputs one by
one. The idea is to start from first index (index = 0) in data[], one
by one fix elements at this index and recur for remaining indexes. Let
the input array be {1, 2, 3, 4, 5} and r be 3. We first fix 1 at index
0 in data[], then recur for remaining indexes, then we fix 2 at index
0 and recur. Finally, we fix 3 and recur for remaining indexes. When
number of elements in data[] becomes equal to r (size of a
combination), we print data[].
Method 2 (Include and Exclude every element)
Like the above method, We create a temporary array data[]. The idea
here is similar to Subset Sum Problem. We one by one consider every
element of input array, and recur for two cases:
The element is included in current combination (We put the element in data[] and increment next available index in data[])
The element is excluded in current combination (We do not put the element and do not change index)
When number of elements in data[] become equal to r (size of a
combination), we print it.