Maximum possible average of an array sub sequence -- Need efficient solution - java

Input
1: array size (1 to 10^5)
2: Number to take average (1 to 10^3)
3: elements in array (1 to 10^5) Non sorted, any order is possible
Output: Maximum possible average of any sub-array.
Eg:
5 3
1 2 3 4 5
o/p = 5
5 4
1 2 3 4 5
o/p = 3
for first example seq will be sum[0,4]=15 and its average with 3 will be 5.
for second example seq will be sum[2,4]=12 and its average with 4 will be 3.
I already have below given solution of o(n^2) but its not working for large inputs.
long max = 0;
for( int m = 0; m < people; m++ )
{
long sum = 0;
for( int n = m; n < people; n++ )
{
sum = sum + chocolateArray[n];
if( sum % boxes == 0 )
{
if( ( sum / boxes ) > max )
{
max = sum / boxes;
}
}
}
}
System.out.println( max );
where people is array size, boxes is average number and chocolateArray is original array.
Please provide efficient solution. I thought to take it through dynamic programming but creating two dimensional array of 10^5 size is causing outofmemory issue.

Since all numbers are positive, the only effective constraint is the divisibility. So the question is asking for the maximum subarray sum that is divisible by m, the number of boxes.
This can be done by creating an array of the cumulative sum, modulo m, then finding two places with the same numbers, as far apart as possible. Since there are at most m values, we can simply store the minimum and maximum index of every possible residue, then take the one with the maximum subarray sum. The code below does that.
cumsum = int[people+1];
minPos = int[boxes];
maxPos = int[boxes];
Arrays.fill(minPos, -1);
Arrays.fill(maxPos, -1);
int residue = 0;
for(int i=0; i<people; i++){
cumsum[i+1] = cumsum[i] + chocolateArray[i]; // For simplicity the array length is 1 longer
residue = cumsum[i+1] % boxes;
if(minPos[residue] == -1) minPos[residue] = i;
maxPos[residue] = i;
}
int max = 0;
for(int i=0; i<boxes; i++){
int sum = cumsum[maxPos[i]+1] - cumsum[minPos[i]+1];
if(sum > max){
max = sum;
}
}
System.out.println(max/boxes);
For example:
People = 5
Boxes = 4
Array = [1, 2, 3, 4, 5]
Cumulative = [1, 3, 6, 10, 15]
Residue = [1, 3, 2, 2, 3]
MinMaxPos[0] = (-1, -1) -> sum = 0 -> avg = 0
MinMaxPos[1] = (0, 0) -> sum = 0 -> avg = 0
MinMaxPos[2] = (2, 3) -> sum = 4 -> avg = 1
MinMaxPos[3] = (1, 4) -> sum = 12 -> avg = 3

Building on #justhalf's brilliant solution. we will be able to do this using a single pass and only a single array
let dp[boxes] be a array of length boxes where dp[i] will hold the minimum sum so far which has i = current_sum % boxes
Since all the numbers are positive number we can store only the first occurrence of a the particular residue since the next time this residue occurs it will be greater that the previous sum.
At each iteration we check if a particular residue has been already found. If yes then then we subtract the current_sum with the previous sum of that residue.
Else we update the sum for the residue and move.
int maxSubArrayAverage(vector<int> people, int boxes)
{
vector<int> dp(boxes, -1);
int max_sum = 0, current_sum = 0;
dp[0] = 0; // if residue is 0 entire current_sum is the choice
for(int i=0; i < people.size(); ++i)
{
current_sum += people[i];
int residue = current_sum % boxes;
if(dp[residue] == -1) // update for the first time
{
dp[residue] = current_sum;
}
else
{
max_sum= max(max_sum, current_sum - dp[residue]);
// cout << i << ' ' << current_sum << ' ' << residue << ' ' << max_average << endl;
}
}
// copy(dp.begin(), dp.end(), ostream_iterator<int>(cout, " "));
// cout << endl;
return max_sum/boxes;
}

Related

How can I efficiently compute the sum of parts of an array of sizes in an arithmetic sequence?

I am trying to find the sum of parts of a given array with a length that is the sum of the first N positive integers for some whole number N. The size of each part for which I am to find the sum are the numbers in said arithmetic sequence. For instance, for an array of length 10, I need to find the sum of the first number, the next two numbers, and so on, until the next N numbers.
Example Input:
[1,4,5,2,6,7,9,8,7,10]
Example Output:
[1,9,15,34]//1, 4+5, 2+6+7, 9+8+7+10
Explanation:
The first sum is 1, the first element (index 0). The sum of the next two numbers is 4 + 5 = 9 (index 1 and 2). The sum of the next three numbers is 2 + 6 + 7 = 15 (index 3, 4, and 5). The sum of the last four numbers is 9 + 8 + 7 + 10 = 34 (index 6, 7, 8, 9).
You can compute the size of the result array using the formula for the sum of an arithmetic sequence, i.e. n(n + 1) / 2.
A prefix sum array can be applied here so so that any range sum can be computed in O(1) time with O(n) precomputation time and space (which is also the overall complexity of this algorithm).
final int[] input = { 1, 4, 5, 2, 6, 7, 9, 8, 7, 10 };
// size * (size + 1) / 2 = input.length
final int size = (-1 + (int) Math.sqrt(1 + 8 * input.length)) / 2;
// derived by quadratic formula
final int[] result = new int[size];
final int[] sum = new int[input.length + 1];
for (int i = 1; i <= input.length; i++) {
sum[i] = sum[i - 1] + input[i - 1];
}
for (int i = 1, j = 0; i <= input.length; i += ++j) {
result[j] = sum[i + j] - sum[i - 1];
}
System.out.println(Arrays.toString(result));
Ideone Demo
The following algorithm is very efficient and does not rely on the summation formula to work (as you had asked about) other than to compute the length of the result array. This should not be a problem since it is basic algebra. If you use a List implementation you would not have to do that.
It also only sums only to the max allowed by the given array. So if you provide an array like
1 2 3 4 5 6 7 8 9 10 11 12 13
It will silently ignore 11 12 and 13 since they don't comprise enough values to continue.
Here is the algorithm with your original data set and the output.
int[] arr = { 1, 4, 5, 2, 6, 7, 9, 8, 7, 10 };
int start = 0; // start of group
int end = 0; // end of group
int[] sol = new int[(int)(-.5 + Math.sqrt(2*arr.length + .25))];
for (int i = 1; i <= sol.length; i++) {
// initialize the sum
int sum = 0;
// compute next end
end += i;
// and sum from start to end
for (int k = start; k < end; k++) {
sum += arr[k];
}
// old end becomes next start
start = end;
sol[i-1] = sum;
}
Prints
[1, 9, 15, 34]

How could we get within a certain range, the maximum number of times, an int is divisible by 2

I am doing the following programming exercise: Strongest even number in an interval. The statement is:
A strongness of an even number is the number of times we can
successively divide by 2 until we reach an odd number starting with an
even number n.
For example, if n = 12, then
12 / 2 = 6
6 / 2 = 3
we divided successively 2 times and we reached 3, so the strongness of
12 is 2.
If n = 16 then
16 / 2 = 8
8 / 2 = 4
4 / 2 = 2
2 / 2 = 1
we divided successively 4 times and we reached 1, so the strongness of
16 is 4 Task
Given a closed interval [n, m], return the even number that is the
strongest in the interval. If multiple solutions exist return the
smallest strongest even number.
Note that programs must run within the alloted server time; a naive
solution will probably time out. Constraints
1 <= n < m <= INT_MAX Examples
for the input [1, 2] return 2 (1 has strongness 0, 2 has strongness 1)
for the input [5, 10] return 8 (5, 7, 9 have strongness 0; 6, 10 have
strongness 1; 8 has strongness 2)
for the input [48, 56] return 48
First I thought to store in a map each number as a key, and the number of times it is divisible by 2, as a value:
import java.util.*;
public class StrongestEvenNumber {
public static int strongestEven/*💪*/(int n, int m) {
System.out.println("n: "+n);
System.out.println("m: "+m);
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i = n, number = 0, strongness = 0; i <= m; i++){
for(number = i, strongness = 0; number % 2 == 0; strongness++){
number /= 2;
}
map.put(i, strongness);
}
Map.Entry<Integer, Integer> maxEntry = null;
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
if(maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0){
maxEntry = entry;
}
}
return maxEntry.getKey();
}
}
However, with large numbers, it runs out of heap memory space, or execution time runs out. For example with:
n: 1180381085
m: 2074186600
Java heap space runs out.
And with:
n: 324243
m: 897653214
Execution time runs out. The execution time exceeds 16000 ms
Then I tried to just store the number which is the most times divisible by 2:
import java.util.*;
public class StrongestEvenNumber {
public static int strongestEven/*💪*/(int n, int m) {
System.out.println("n: "+n);
System.out.println("m: "+m);
int maxStrongness = 0, maxNumber = 0;
for(int i = n, number = 0, strongness = 0; i <= m; i++){
for(number = i, strongness = 0; number % 2 == 0; strongness++){
number /= 2;
}
if(strongness > maxStrongness){
maxStrongness = strongness;
maxNumber = i;
}
}
return maxNumber;
}
}
Indeed it solves the heap space difficulty, however the execution time runs out behaviour stills happening.
For example with:
n: 200275492
m: 1590463313
The execution time exceeds 16000 ms
I have also read:
Finding Key associated with max Value in a Java Map
Get the key for the maximum value in a HashMap using Collections
https://math.stackexchange.com/questions/2589831/how-many-times-can-i-divide-a-number-by-another
Number of times all the numbers in an array are divisible by 2
optimize code to get the number of integers within given range that are divisible by integer
Well, the strongness of a value x is n when x is represented as
x = k * 2**n
knowing this we can check all powers of 2 (i.e. 1, 2, 4, 8, ...) if we can find any k such that
from <= k * 2**n <= to
Code:
private static int strongestEven(int from, int to) {
if (to < from)
return -1; // Or throw exception
// best power of 2 we can insert between [to..from] as k * best
int best = 1;
while (true) {
int ceiling = from / best + (from % best == 0 ? 0 : 1);
int floor = to / best;
if (ceiling > floor) {
best = best / 2;
return best * (to / best);
}
best *= 2;
}
}
Tests:
[ 1, 2] => 2
[ 5, 10] => 8
[48, 56] => 48
[80, 100] => 96
[97, 100] => 100
Finally,
[1180381085, 1590463313] => 1342177280
we have 1342177280 == 5 * 268435456 == 5 * 2**28 so the strongest number within [1180381085, 1590463313] range has strongness 28
Please, note, that the algorithm has O(log(to)) time complexity that's why will do even if we turn all int into long
The strongness is actually the number of trailing zeros in the binary representation of the number. You can use the java.lang.Integer.numberOfTrailingZeros to get it.
And as you want to test the even numbers, you can skipp the odd numbers in your loop.
public class StrongestEvenNumber {
public static int strongestEven(int n, int m) {
int maxStrongness = 0, maxNumber = 0;
for(int i = n%2==0?n:n+1, strongness = 0; i <= m; i=i+2){
strongness = Integer.numberOfTrailingZeros(i);
if(strongness > maxStrongness){
maxStrongness = strongness;
maxNumber = i;
}
}
return maxNumber;
}
This runs in the allocated time:
Completed in 13190ms

How to get the kth term in N Combination R [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
How do I get the kth combination inNCR. without iterating through all possible outcomes. e.g. say I have 3C2 for 3 positions and 2identical-items. I am aware it's [011],[101] and [110]. how do I get e.g. the 2nd term(k=1) which is [101] using a method?
constraints(R < N k >= 0 and k < P where P = NCR).
NB:[101] is the 2nd term(in ascending/lexicographical order) because 011 = 3,101 = 5 ,110 = 6
in decimal. so basically the goal is to get what number k in NCR is,
because every kth output from NCR can be represented as a number.
Yes, you are correct when you say:
because every kth output from NCR can be represented as a number.
There is a bijection from the set of integers 1 to # of combs/perms to the entire set of combs/perms. Finding the specific index of a particular comb/perm is sometimes referred to as getting the rank. According to the example that you have in your question, these are ordinary permutations. Moreover when you mention ascending order, you are referring to the lexicographical order.
It is a straightforward exercise in counting to obtain the nth ordinary permutation of a given set. We first need to obtain the total number of permutations using the well established formula:
P(n, r) = n! / (n - r)!
This next part is the key observation that allows us to quickly obtain each element of our target permutation.
If we look at all permutations of our set of n choose r, there will be n groups that are only different by a permutation of the n elements.
For example, if we look at the first two group of the permutations of [0 1 2 3] choose 3, we have:
[,0] [,1] [,2]
[0,] 0 1 2
[1,] 0 1 3
[2,] 0 2 1
[3,] 0 2 3
[4,] 0 3 1
[5,] 0 3 2
[6,] 1 0 2
[7,] 1 0 3
[8,] 1 2 0
[9,] 1 2 3
[10,] 1 3 0
[11,] 1 3 2
Note that the last permutations are simply the first 6 permutations of the set [1 0 2 3].. that is, 0 is mapped to 1, 1 is mapped to 0, and the final 2 elements are mapped to themselves.
This pattern continues as we move to the right only instead of n identical groups, we will get n - 1 similar groups for the second column, n -2 for the third, and so on.
So to determine the first element of our permutation, we need to determine the 1st group. We do that by simply dividing the number of permutations by n. For our example above of permutations of 4 choose 3, if we were looking for the 15th permutation, we have the following for the first element:
Possible indices : [0 1 2 3]
P(4, 3) = 24
24 / 4 = 6 (elements per group)
15 / 6 = 2 (integer division) 2 means the 3rd element here (base zero)
Now that we have used the 3rd element, we need to remove it from our array of possible indices. How do we get the next element?
Easy, we get our next subindex by subtracting the product of the group we just found and the elements per group from our original index.
Possible indices : [0 1 3]
Next index is 15 - 6 * 2 = 3
Now, we just repeat this until we have filled all entries:
Possible indices : [0 1 3]
Second element
6 / 3 = 2 (elements per group)
3 / 2 = 1
Next index is 3 - 3 * 1 = 0
Possible indices : [0 3]
Third element
2 / 2 = 1
0 / 1 = 0
So our 15th element is : [2 1 0]
Here is a C++ implementation that should be pretty easy to translate to Java:
double NumPermsNoRep(int n, int k) {
double result = 1;
double i, m = n - k;
for (i = n; i > m; --i)
result *= i;
return result;
}
std::vector<int> nthPermutation(int n, int r, double myIndex) {
int j = 0, n1 = n;
double temp, index1 = myIndex;
std::vector<int> res(r);
temp = NumPermsNoRep(n, r);
std::vector<int> indexVec(n);
std::iota(indexVec.begin(), indexVec.end(), 0);
for (int k = 0; k < r; ++k, --n1) {
temp /= n1;
j = (int) std::trunc(index1 / temp);
res[k] = indexVec[j];
index1 -= (temp * (double) j);
indexVec.erase(indexVec.begin() + j);
}
}
These concepts extends to other types of combinatorial problems, such as finding the nth combination, or permutation with repetition, etc.
The time complexity is O(kn), space is O(n)
public static void main(String[] args) {
//n = 4, r = 2, k = 3
int[] ret1 = getKthPermutation(4, 2, 3);
//ret1 is [1,0,0,1]
//n = 3, r = 2, k = 1
int[] ret2 = getKthPermutation(3, 2, 1);
//ret2 is [1,0,1]
}
static int[] getKthPermutation(int n, int r, int k) {
int[] array = new int[n];
setLastN(array, r, 1);
int lastIndex = n - 1;
for(int count = 0; count < k; count++) {
int indexOfLastOne = findIndexOfLast(array, lastIndex, 1);
int indexOfLastZero = findIndexOfLast(array, indexOfLastOne, 0);
array[indexOfLastOne] = 0;
array[indexOfLastZero] = 1;
//shortcut: swap the part after indexOfLastZero to keep them sorted
int h = indexOfLastZero + 1;
int e = lastIndex;
while(h < e) {
int temp = array[h];
array[h] = array[e];
array[e] = temp;
h++;
e--;
}
}
return array;
}
//starting from `from`, and traveling the array forward, find the first `value` and return its index.
static int findIndexOfLast(int[] array, int from, int value) {
for(int i = from; i > -1; i--)
if(array[i] == value) return i;
return -1;
}
//set the last n elements of an array to `value`
static void setLastN(int[] array, int n, int value){
for(int i = 0, l = array.length - 1; i < n; i++)
array[l - i] = value;
}
This is an adaption of the very typical "find the kth permation" algorithm.
I will try to explain the general idea (yours is a special case as there are only two types of elements: 0 and 1).
Lets say I have [2,1,6,4,7,5]. What is the next smallest permutation that is bigger than the current one? Why do I concern the next smallest permutation bigger than current one? Because if you start with the smallest permutation [1,2,4,5,6,7] and you repeat the action (find the smallest bigger than current) k times, you will find k+1 th smallest permutation.
Now, since the one I am looking for needs to be bigger than current one, I need to increment the current one. To keep the incrementation as small as possible, I am going to try to modify 5 (last one). Now, I cannot just change 5 to a random value, I can only swap it with some digit before it.
If I swap 5 with a bigger number before it, say 7, then I will get [2,1,6,4,5,7], which is smaller than current one. Now obviously I need to swap 5 with some smaller digit before it, but which one? If I swap 5 with 2, I get [5,1,6,4,7,2], this increment is too big. I need to swap 5 with a "lower digit" to keep the increment as small as possible. Thats leads us to find the first(lowest) digit (from right to left) that is smaller than 5. In this case I would need to swap 5 with 4 and get [2,1,6,5,7,4]. This way, I can make the impact of "swap" small. Now the prefix is decided [2,1,6,5. There is no smaller prefix. We need to deal with suffix 7,4]. Clearly, if we sort the suffix and make it 4,7], then we are done.
In our case, there are two differences:
1. we need to swap the last 1, because you cannot make the permutation bigger by swapping the a zero with any digit before it.
2. we can always sort the suffix using a shortcut as shown in the code. I will leave it to you:)
public static String lexicographicPermutation(String str, long n) {
final long[] factorials = { 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600 };
n--;
char[] arr = str.toCharArray();
for (int i = 0; i < arr.length - 1; i++) {
long fact = factorials[arr.length - i - 2];
long p = i + n / fact;
n %= fact;
for (int j = i + 1; j <= p; j++)
swap(arr, i, j);
}
return new String(arr);
}
private static void swap(char[] arr, int i, int j) {
char tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
You can replace STR with required string. In the given example, 1st permutation is "abcdefghijklm" (this is a string with 13 chars), 13!st permutation is reverse string "mlkjihgfedcba" and 100st permutation is "abcfklgmeihjd".
To realise this soulution just google Factorial number system. This is a key to solve this problem. This is a Project Euler: Problem 24.
Demo:
for(int i = 1; i <= 6; i++)
System.out.println(lexicographicPermutation("110", i));
1 - 110
2 - 101
3 - 110
4 - 101
5 - 011
6 - 011
for(int i = 1; i <= 6; i++)
System.out.println(lexicographicPermutation("abc", i));
1 - abc
2 - acb
3 - bac
4 - bca
5 - cab
6 - cba

Correct Algorithm for Game of two stacks on HackerRank

I just attempted a stack based problem on HackerRank
https://www.hackerrank.com/challenges/game-of-two-stacks
Alexa has two stacks of non-negative integers, stack A and stack B where index 0 denotes the top of the stack. Alexa challenges Nick to play the following game:
In each move, Nick can remove one integer from the top of either stack A or B stack.
Nick keeps a running sum of the integers he removes from the two stacks.
Nick is disqualified from the game if, at any point, his running sum becomes greater than some integer X given at the beginning of the game.
Nick's final score is the total number of integers he has removed from the two stacks.
find the maximum possible score Nick can achieve (i.e., the maximum number of integers he can remove without being disqualified) during each game and print it on a new line.
For each of the games, print an integer on a new line denoting the maximum possible score Nick can achieve without being disqualified.
Sample Input 0
1 -> Number of games
10 -> sum should not exceed 10
4 2 4 6 1 -> Stack A
2 1 8 5 -> Stack B
Sample Output
4
Below is my code I tried the greedy approach by taking the minimum element from the top of the stack & adding it to the sum. It works fine for some of the test cases but fails for rest like for the below input
1
67
19 9 8 13 1 7 18 0 19 19 10 5 15 19 0 0 16 12 5 10 - Stack A
11 17 1 18 14 12 9 18 14 3 4 13 4 12 6 5 12 16 5 11 16 8 16 3 7 8 3 3 0 1 13 4 10 7 14 - Stack B
My code is giving 5 but the correct solution is 6 the elements popped out in series are 19,9,8,11,17,1
First three elements from stack A & then from Stack B.
**
I don't understand the algorithm It appears like DP to me can anyone
help me with the approach/algorithm?
**
public class Default {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int numOfGames = Integer.parseInt(br.readLine());
for (int i = 0; i < numOfGames; i++) {
String[] tmp = br.readLine().split(" ");
int numOfElementsStackOne = Integer.parseInt(tmp[0]);
int numOfElementsStackTwo = Integer.parseInt(tmp[1]);
int limit = Integer.parseInt(tmp[2]);
int sum = 0;
int popCount = 0;
Stack<Integer> stackOne = new Stack<Integer>();
Stack<Integer> stackTwo = new Stack<Integer>();
String[] stOne = br.readLine().split(" ");
String[] stTwo = br.readLine().split(" ");
for (int k = numOfElementsStackOne - 1; k >= 0; k--) {
stackOne.push(Integer.parseInt(stOne[k]));
}
for (int j = numOfElementsStackTwo - 1; j >= 0; j--) {
stackTwo.push(Integer.parseInt(stTwo[j]));
}
while (sum <= limit) {
int pk1 = 0;
int pk2 = 0;
if (stackOne.isEmpty()) {
sum = sum + stackTwo.pop();
popCount++;
} else if (stackTwo.isEmpty()) {
sum = sum + stackOne.pop();
popCount++;
}
else if (!stackOne.isEmpty() && !stackTwo.isEmpty()) {
pk1 = stackOne.peek();
pk2 = stackTwo.peek();
if (pk1 <= pk2) {
sum = sum + stackOne.pop();
popCount++;
} else {
sum = sum + stackTwo.pop();
popCount++;
}
} else if(stackOne.isEmpty() && stackTwo.isEmpty()){
break;
}
}
int score = (popCount>0)?(popCount-1):0;
System.out.println(score);
}
}
}
Ok I will try to explain an algorithm which basically can solve this issue with O(n), you need to try coding it yourself.
I will explain it on the simple example and you can reflect it
1 -> Number of games
10 -> sum should not exceed 10
4 2 4 6 1 -> Stack A
2 1 8 5 -> Stack B
First you will need to creat 2 arrays, the array will contain the summation of all the number up to its index of the stack, for example for stack A you will have this array
4 6 10 16 17 //index 0 ->4
Same will be done for stack B
2 3 11 16
then for each array start iterating from the end of the array until you reach a number less than or equal to the "sum you should not exceed"
now your current sum is the sum of the point you reached in both arrays, should be 10 +3 = 13 so in order to reach 10 will absolutely need to remove more entries
to remove the additional entries we will be moving the indexes on the array again, to decide which array to move it's index take the entry you are pointing at (10 for array 1 and 3 for array 2) and device it by index+1 (10/3 ~ 3) , (3/2 ~1) then move the index for the highest value and recalculate the sum
Suppose we have:
a = 1 1 1 211 2
b = 1 85
and maxSum = 217
Now, on calculating prefix sums,
a' = 1 2 3 214 216
and b' = 1 86
current sum = 86+216 > 217
so to decide which index to remove, we compare `
216/5~43.2` and `86/2=43`,
so we move pointer in a'. BUT, that doesn't solve it - `
214+86 is still > 217!!`
Had we removed 86, it would've been better! So we should always go ahead by removing the one which has larger difference with previous element!
In case both values are equal its logical to move the index on the value which has larger difference with its previous ( remember we are moving the index in reverse order).
the result will be the sum of the indexes +2.
This solution works great.... i hope it helps ...
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int g = sc.nextInt();
for (int tc = 0; tc < g; tc++) {
int n = sc.nextInt();
int m = sc.nextInt();
int x = sc.nextInt();
int[] a = readArray(sc, n);
int[] b = readArray(sc, m);
System.out.println(solve(a, b, x));
}
sc.close();
}
static int[] readArray(Scanner sc, int size) {
int[] result = new int[size];
for (int i = 0; i < result.length; i++) {
result[i] = sc.nextInt();
}
return result;
}
static int solve(int[] a, int[] b, int x) {
int lengthB = 0;
int sum = 0;
while (lengthB < b.length && sum + b[lengthB] <= x) {
sum += b[lengthB];
lengthB++;
}
int maxScore = lengthB;
for (int lengthA = 1; lengthA <= a.length; lengthA++) {
sum += a[lengthA - 1];
while (sum > x && lengthB > 0) {
lengthB--;
sum -= b[lengthB];
}
if (sum > x) {
break;
}
maxScore = Math.max(maxScore, lengthA + lengthB);
}
return maxScore;
}
}
solution in python3
# stack implementation
class Stack:
lis = []
def __init__(self, l):
self.lis = l[::-1]
def push(self, data):
self.lis.append(data)
def peek(self):
return self.lis[-1]
def pop(self):
self.lis.pop()
def is_empty(self):
return len(self.lis) == 0
# number of test cases
tests = int(input())
for i in range(tests):
na, nb, x = map(int, input().split(' '))
a = list(map(int, input().split(' ')))
b = list(map(int, input().split(' ')))
temp = []
stk_a = Stack(a)
stk_b = Stack(b)
score = 0
count = 0
# first taking elements from stack A , till score becomes just less than desired total
for j in range(len(a)):
if score + stk_a.peek() <= x:
score += stk_a.peek()
count += 1
temp.append(stk_a.peek())
# storing the popped elements in temporary stack such that we can again remove them from score
# when we find better element in stack B
stk_a.pop()
# this is maximum number of moves using only stack A
max_now = count
# now iterating through stack B for element lets say k which on adding to total score should be less than desired
# or else we will remove each element of stack A from score till it becomes just less than desired total.
for k in range(len(b)):
score += stk_b.peek()
stk_b.pop()
count += 1
while score > x and count > 0 and len(temp) > 0:
count = count - 1
score = score - temp[-1]
temp.pop()
# if the score after adding element from stack B is greater than max_now then we have new set of moves which will also lead
# to just less than desired so we should pick maximum of both
if score <= x and count > max_now:
max_now = count
print(max_now)
I see that there exist a solution and you marked it as correct, but I have a simple solution
add all elements from stack one that satisfy condition <= x
every element you add push it on stack called elements_from_a
set counter to size of stack
try add elements from stack b if sum > x so remove last element you added you can get it from stack elements_from_a
increment bstack counter with each add , decrements from astack with each remove
compare sum of steps with count and adjust count return count
here is code sample for the solution :
def twoStacks(x, a, b):
sumx = 0
asteps = 0
bsteps = 0
elements = []
maxIndex = 0
while len(a) > 0 and sumx + a[0] <= x :
nextvalue = a.pop(0)
sumx+=nextvalue
asteps+=1
elements.append(nextvalue)
maxIndex = asteps
while len(b) > 0 and len(elements) > 0:
sumx += b.pop(0)
bsteps+=1
while sumx > x and len(elements) > 0 :
lastValue = elements.pop()
asteps-=1
sumx -= lastValue
if sumx <= x and bsteps + asteps > maxIndex :
maxIndex = bsteps + asteps
return maxIndex
I hope this is more simple solution.
void traversal(int &max, int x, std::vector<int> &a, int pos_a,
std::vector<int> &b, int pos_b) {
if (pos_a < a.size() and a[pos_a] <= x) {
max = std::max(pos_a + pos_b + 1, max);
traversal(max, x - a[pos_a], a, pos_a + 1, b, pos_b);
}
if (pos_b < b.size() and b[pos_b] <= x) {
max = std::max(pos_a + pos_b + 1, max);
traversal(max, x - b[pos_b], a, pos_a, b, pos_b + 1);
}
}
int twoStacks(int x, std::vector<int> &a, std::vector<int> &b) {
int max = 0;
traversal(max, x, a, 0, b, 0);
return max;
}
A recursion solution, easy to understand. This solution takes the 2 stacks as a directed graph and traversal it.
The Accepted Answer is Wrong. It fails for the below test case as depicted in the image.
For the test case given, if maximum sum should not exceed 10. Then correct answer is 5. But if we follow the approach by Amer Qarabsa, the answer would be 3. We can follow Geeky coder approach.

Find middle element in Count sorted array

So, I have array like this:
a[1] = 2
a[4] = 3
a[8] = 1
which represent this sequence 1 1 4 4 4 8
And I need to find middle element, or element before (for odd and even);
In this example its 4.
How can I do this quick?
My code is very slow:
static int B(int[] array, int size) {
int c = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i]; j++) {
c++;
if (c == size / 2) {
return i;
}
}
}
}
Traverse original array and add all values
a[1] = 2
a[4] = 3
a[8] = 1
sum = 6
Divide sum by 2 (find mid)
mid = 6/2 = 3
Traverse original array and subtract value from sum
check if ans <= 0
if true print index
else continue to next
For an even less efficient way to do it, run one pass through and keep updating :)
Javascript (since I'm Java challenged):
var a=[]
a[1] = 2
a[4] = 3
a[8] = 1
a[9] = 2
a[10] = 3
a[11] = 1
//1 1 4 4 4 8 9 9 10 10 10 11
function middle (arr){
var stack = [],
total = 0,
tmp,
tmpChange,
middle = 0,
change = 0,
middleElement
for (i in arr){
stack.push([i, arr[i]])
total += arr[i]
tmp = Math.ceil(total/2)
change = tmp - middle
middle = tmp
while (change){
tmpChange = stack[0][1] - change
if (tmpChange >= 0) {
stack[0][1] = tmpChange
change = 0
}
else {
change -= stack[0][1]
stack.splice(0,1)
}
}
middleElement = stack[0][0]
}
return middleElement
}
console.log(middle(a))

Categories

Resources