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))
Related
A non-empty array A consisting of N integers is given. The array contains an odd number of elements, and each element of the array can be paired with another element that has the same value, except for one element that is left unpaired.
For example, in array A such that:
A[0] = 9 A[1] = 3 A[2] = 9
A[3] = 3 A[4] = 9 A[5] = 7
A[6] = 9
the elements at indexes 0 and 2 have value 9,
the elements at indexes 1 and 3 have value 3,
the elements at indexes 4 and 6 have value 9,
the element at index 5 has value 7 and is unpaired.
Write a function:
class Solution { public int solution(int[] A); }
that, given an array A consisting of N integers fulfilling the above conditions, returns the value of the unpaired element.
For example, given array A such that:
A[0] = 9 A[1] = 3 A[2] = 9
A[3] = 3 A[4] = 9 A[5] = 7
A[6] = 9
the function should return 7, as explained in the example above.
Write an efficient algorithm for the following assumptions:
N is an odd integer within the range [1..1,000,000];
each element of array A is an integer within the range [1..1,000,000,000];
all but one of the values in A occur an even number of times.
MY SOLUTION
My solution fails at these scenarios, I am willing from SO community to please guide me how to think this problem so that i can overcome these failures
class Solution {
public int solution(int[] A) {
int[] result = new int[(int) Math.ceil((double)A.length/2)];
for(int x = 0 ; x < result.length ; x++ ){
result[x] = -1;
}
for(int x = 0 ; x < A.length ; x++ ){
for(int y = 0 ; y < result.length ; y++){
if(result[y] > -1 && result[y]== A[x])
{
result[y] = -2;
break;
}
if(result[y] == -1 )
{
result[y] = A[x];
break;
}
}
}
for(int x = 0 ; x < result.length ; x++ ){
if(result[x] > -1){
return result[x];
}
}
return -1;
}
}
FAILURES
medium random test n=100,003
Killed. Hard limit reached: 7.000 sec.
big random test n=999,999, multiple repetitions
Killed. Hard limit reached: 14.000 sec.
big random test n=999,999
Killed. Hard limit reached: 19.000 sec.
If it is guaranteed that the input has only one unpaired element, it is very simple to identify it by doing an XOR of all elements.
int x = A[0];
for ( int i = 1; i < A.length; i++ )
x = x ^ A[i];
The resulting value is the one which is not paired.
Example:
public static void main (String[] args) throws java.lang.Exception
{
int[] A = {9, 3, 9, 2, 4, 2, 4, 7, 3};
int x = A[0];
for ( int i = 1; i < A.length; i++ )
x = x ^ A[i];
System.out.println(x);
}
Output is 7.
Time complexity is O(n)
This works because the XOR of a number with itself is zero.
The most effective solution exploits interesting property of bitwise XOR operation:
a xor a = 0
for any value of a, so xor'ing all array items just gives unpaired value
public int solution(int[] A) {
int result = 0;
for(int x = 0 ; x < A.length ; x++ )
result ^= A[x];
return result;
}
Recently, I had encountered an interesting programming puzzle which had some good twist and turn mentioned in the puzzle. Below the question which amazed me, I simply eager to know if any relevant solution probably in java is feasible for below scenario.
Problem statement:
There is a grid of dimension m*n, initially, a bacterium is present at the bottom left cell(m-1,0) of the grid with all the other cells empty. After every second, each bacteria in the grid divides itself and increases the bacteria count int the adjacent(horizontal,vertical and diagonal) cells by 1 and dies.
How many bacteria are present at the bottom right cell(m-1,n-1) after n-1 seconds?
I had taken references from
https://www.codechef.com/problems/BGH17
but failed to submit the solution
Below is the image for more insite of problem
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class BacteriaProblem {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Number of Rows: ");
int m = sc.nextInt();
System.out.println("Number of Columns: ");
int n = sc.nextInt();
int[][] input = new int[m][n];
input[m - 1][0] = 1;
Stack<String> stack = new Stack<>();
stack.push(m - 1 + "~" + 0);
reproduce(stack, input, n - 1);
System.out.println("Value at Bottom Right corner after n-1 secs: " + input[m - 1][n - 1]);
}
private static void reproduce(Stack<String> stack, int[][] input, int times) {
//exit condition
if (times < 1) {
return;
}
//bacteria after splitting
List<String> children = new ArrayList<>();
//reproduce all existing bacteria
while (!stack.isEmpty()) {
String[] coordinates = stack.pop().split("~");
int x = Integer.parseInt(coordinates[0]);
int y = Integer.parseInt(coordinates[1]);
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) continue;
split(input, x + i, y + j, children);
}
}
input[x][y]--;
}
//add all children to stack
for (String coord : children) {
stack.push(coord);
}
//reduce times by 1
reproduce(stack, input, times - 1);
}
private static void split(int[][] input, int x, int y, List<String> children) {
int m = input.length;
int n = input[0].length;
if (x >= 0 && x < m && y >= 0 && y < n) {
input[x][y]++;
children.add(x + "~" + y);
}
}
}
Well, I was asked this question in an Online Hackerrank test and couldn't solve it at that time.
I did later try to code it and here's the soln in C++,
long countBacteriasAtBottomRight(int m, int n){
long grid[m][n];
// Set all to 0, and only bottom left to 1
for (int i=0; i<m; i++){
for (int j=0; j<n; j++){
grid[i][j] = 0;
}
}
grid[m-1][0] = 1;
// Start the cycle, do it for (n-1) times
int time = n-1;
vector<long> toBeUpdated;
while (time--){
cout << "\n\nTime: " << time;
for (int i=0; i<m; i++){
for (int j=0; j<n; j++){
while (grid[i][j] > 0){
grid[i][j]--;
// upper left
if (i > 0 && j > 0){
toBeUpdated.push_back(i-1);
toBeUpdated.push_back(j-1);
}
// upper
if (i > 0){
toBeUpdated.push_back(i-1);
toBeUpdated.push_back(j);
}
// upper right
if (i > 0 && j < n-1){
toBeUpdated.push_back(i-1);
toBeUpdated.push_back(j+1);
}
// left
if (j > 0){
toBeUpdated.push_back(i);
toBeUpdated.push_back(j-1);
}
// bottom left
if (i < m-1 && j > 0){
toBeUpdated.push_back(i+1);
toBeUpdated.push_back(j-1);
}
// bottom
if (i < m-1){
toBeUpdated.push_back(i+1);
toBeUpdated.push_back(j);
}
// bottom right
if (i < m-1 && j < n-1){
toBeUpdated.push_back(i+1);
toBeUpdated.push_back(j+1);
}
// right
if (j < n-1){
toBeUpdated.push_back(i);
toBeUpdated.push_back(j+1);
}
};
}
}
// Update all other cells
for (int k=0; k<toBeUpdated.size(); k+=2){
grid[toBeUpdated[k]][toBeUpdated[k+1]]++;
}
for (int i=0; i<m; i++){
cout << endl;
for (int j=0; j<n; j++)
cout << grid[i][j] << " ";
}
// Clear the temp vector
toBeUpdated.clear();
};
return grid[m-1][n-1];
}
The starting situation only has a value in the left-most column 0. We need to know the situation in the right-most column n-1 after time n-1. This means that we only have to look at each column once: column x at time x. What happens to column x after time x is no longer important. So we go from left to right, adding up the cells from the previous column:
1
1 8
1 7 35
1 6 27 104
1 5 20 70 230
1 4 14 44 133 392
1 3 9 25 69 189 518
1 2 5 12 30 76 196 512
1 1 2 4 9 21 51 127 323 ...
You will also notice that the result for the last cell is only influenced by two cells in the previous column, and three in the one before that, so to calculate the end result for e.g. the case n=9, you only need to calculate the values in this triangle:
1
1 4 14
1 3 9 25 69
1 2 5 12 30 76 196
1 1 2 4 9 21 51 127 323
However high the grid is, we only ever have to go up n/2 (rounded up) rows. So the total number of sums we have to calculate is n2/4, or n×m if m < n/2.
Also note that we don't have to store all these values at once, because we go column by column from left to right. So we only need a one-dimensional array of size n/2, and the current values in it are transformed like this (e.g. going from column 4 to 5 in the example above):
[4, 5, 3, 1] (0) -> 0 + 5 - 0 = 5
[9, 5, 3, 1] (5) -> 9 + 3 - 5 = 7
[9,12, 3, 1] (7) -> 12 + 1 - 7 = 6
[9,12, 9, 1] (6) -> 9 + 0 - 6 = 3
[9,12, 9, 4] (3) -> 4 + 0 - 3 = 1
[9,12, 9, 4, 1] (1) (additional value is always 1)
where we iterate over the values from left to right, add up the value to the left and right of the current element, subtract a temporary variable which is initialized to 0, store the result in a temporary variable, and add it to the current element.
So the theoretical time complexity is O(n2) or O(n.m) and the space complexity is O(n) or O(m), whichever is smaller. In real terms, the number of steps is n2/4 and the required space is n/2.
I don't speak Java, but here's a simple JavaScript code snippet which should easily translate:
function bacteria(m, n) {
var sum = [1];
for (var col = 1; col < n; col++) {
var temp = 0;
var height = Math.min(col + 1, n - col, m);
if (height > sum.length) sum.push(0);
for (var row = 0; row < height; row++) {
var left = row > 0 ? sum[row - 1] : 0;
var right = row < sum.length - 1 ? sum[row + 1] : 0;
temp = left + right - temp;
sum[row] += temp;
}
}
return sum[0];
}
document.write(bacteria(9, 9));
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;
}
This is a problem from SPOJ. I am getting TLE. Need help to improve its time complexity. There is one test-case that i know will fail. But I will take care of it after the time complexity is reduced.
Ada the Ladybug was on a trip with her friends. They each bought a souvenir there. As all of them are mathematicians, everybody bought a number. They want to modify the numbers to have some connection between each other. They have decided to modify the numbers sou they would have their GCD greater than 1 ( gcd(a1,a2,a3,...,aN) > 1). Anyway it is not easy to change a number - the only thing they can do is to go to a proffesor in mathematics, which could forge a number A into number A+1 or A-1. As this operation is not cheap, they want to minimize number of such operations. A number might be forged any number of times.
NOTE: gcd(a,0)==a (so gcd of two 0 is also 0)
Input
The first line contains an integer 1 ≤ N ≤ 3*10^5, the number of friend who were on trip (and also the number of numbers).
The second line contains N integers 0 ≤ a_i ≤ 10^6
Output
Print a single line with minimum number of operations to make a connection between all numbers.
Example Input
5
3 9 7 6 31
Example Output
2
Example Input 2
9
3 4 5 7 8 9 11 12 13
Example Output 2
6
Example Input 3
5
7 7 11 17 1
Example Output 3
5
APPROACH
First i find the primes upto (largest/2 + 1) element in the given array of numbers(using function findPrimes()). And then for every element in the array, find how many operations are going to be needed for each of the primes to be its divisor. The smallest summation for each prime, I am printing as solution.
CODE
import java.io.*;
public class Main
{
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int largest = Integer.MIN_VALUE;
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
String[] strArr = br.readLine().split(" ");
for(int i = 0 ; i < n ; i++)
{
arr[i] = Integer.parseInt(strArr[i]);
if(arr[i] > largest)
{
largest = arr[i];
}
}
func(n,arr,largest);
}
public static void func(int n,int[] arr,int largest)
{
int[] primes = findPrimes(largest / 2 + 1);
//int[] primes = findPrimes((int)Math.sqrt(largest));
int lenOfPrimes = primes.length;
int[] mat = new int[lenOfPrimes];
for(int j = 0 ; j < lenOfPrimes ; j++)
{
if(arr[0] < primes[j])
{
mat[j] = primes[j] - arr[0];
}
else if(arr[0] % primes[j] == 0)
{
mat[j] = 0;
}
else
{
int rem = arr[0] % primes[j];
mat[j] = Math.min(rem,primes[j] - rem);
}
}
for(int i = 1 ; i < n ; i++)
{
for(int j = 0 ; j < lenOfPrimes ; j++)
{
if(arr[i] < primes[j])
{
mat[j] = mat[j] + primes[j] - arr[i];
}
else if(arr[i] % primes[j] == 0)
{
mat[j] = mat[j] + 0;
}
else
{
int rem = arr[i] % primes[j];
mat[j] += Math.min(rem,primes[j] - rem);
}
}
}
int smallest = Integer.MAX_VALUE;
for(int i = 0 ; i < lenOfPrimes ;i++)
{
if(mat[i] < smallest)
smallest = mat[i];
}
System.out.println(smallest);
}
public static int[] findPrimes(int upto)
{
boolean[] primes = new boolean[upto + 1];
for(int i = 0 ; i < upto + 1 ; i++)
primes[i] = true;
int count = 0;
primes[0] = primes[1] = false;
int limit = (int)Math.sqrt(upto + 1);
for(int i = 2 ; i < upto + 1; i++)
{
if(primes[i] == true)
{
count++;
if(i <= limit)
{
for(int j = i * i ; j < upto + 1 ; j += 2 * i)
{
primes[j] = false;
}
}
}
}
int[] primeContainer = new int[count];
int index = 0;
for(int i = 2 ; i < upto + 1 ; i++)
{
if(primes[i] == true)
{
primeContainer[index++] = i;
if(index == count)
break;
}
}
return primeContainer;
}
}
The solution that you are trying will give you correct answer. But since there are many prime numbers till 1000000, (~ 78000) hence 78000*300000 will definately give you TLE.
Try to think in terms of sieve. The sieve of eratosthenes works in O(nlogn) time.
Now you would have already figured out that you would change numbers such that it is divisible by some prime number. (As in your algorithm you are considering only prime numbers). So now lets take a prime number say 7. Now you need to find number of transformation of numbers from 0 to 3, because you need to change these numbers to 0. Similarly you need to find number of numbers from 4 to 10 as you will change them to 7 to get them divisible by 7 considering minimum operations. Similarly you would do the same to numbers from 11 to 17, changing them to 14, and so on for rest of the numbers till 1000000. You need to do the same for all prime numbers. This can be achieved using sieve.
The number of operations in this case will be n/2 + n/3 + n/5 + n/7 + n/11 + .... ~ nlogn.
You can read more about sieve from here: https://www.geeksforgeeks.org/sieve-of-eratosthenes/
May be its too late but let me answer this.
I was able to sole this problem using below approach.
My Java Solution take 3.8 S on SPOJ for all 15 test cases combine.
1.Find prime divisors of n in O(log n)
Source https://www.geeksforgeeks.org/prime-factorization-using-sieve-olog-n-multiple-queries/
2. While computing factorization store prime divisors in array let say UniquePrimeWhicheDividsAtleastOneNumber[]
here is a catch always keep 2 in this UniquePrimeWhicheDividsAtleastOneNumber if its not available.
UniquePrimeWhicheDividsAtleastOneNumber[0]=2
3. now you can loop through these primes and find the sum of smallest reminders by these primes.
long minTemp = 0, minAns = Long.MAX_VALUE;
for (int i = 0; i < UniquePrimeWhicheDividsAtleastOneNumber.length; i++) {
for (int j = 0; j < n; j++) {
int rem = InputNumbers[j] % UniquePrimeWhicheDividsAtleastOneNumber[i];
minTemp += Math.min(rem, UniquePrimeWhicheDividsAtleastOneNumber[i] - rem);
if (minTemp > minAns)
break;// no need to compute sum of reminders if it exceeded the current minimum.
}
minAns = Math.min(minAns, minTemp);
minTemp = 0;
}
minAns --> is your answer.
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.