Find the Largest Contingous Sub Array using the Sliding Window Approach - arrays

i am a bit confused on a sliding window problem, the problem statement is relatively simple, given a parameter k where k is the size of the window, find the largest sum possible.
For example
array[] = {4,2,1,7,8,1,2,7,1,0} k = 3, the largest contingous sub array is {7,8,1} which is equal to 16
I have the code, here but I do not understand one line.
*public static int findMaxSumSubarray(int[] arr, int k)
{
int currentSum = 0;
int max = Integer.MIN_VALUE;
for(int i = 0; i<arr.length;++i)
{
currentSum += arr[i];
/*
lets take an array example let arr = {4,2,1,7,8,1,2,7,1,0}
when i is at k-1 then we have effectively covered a valid subset, lets say
k = 3, when i moves to the third element which is 1, a valid subset has been
covered
*/
if(i >= k - 1)
{
max = Math.max(max,currentSum);
currentSum -= arr[i - (k-1)];
}
}
return max;
}**
The line i don't quite understand is currentSum -= arr[i-(k-1)]
Can someone please provide a small desk check/example of what is happening here it will greatly be appreciated
My understanding
Lets take our previous array = {4,2,1,7,8,1,2,7,1,0}
We will iterate until element at index 2, we get 4+2+1, thus we have covered a valid window size, once this is done, the compiler moves to the if statement,
since i is obviously less than or equal to k-1 we will execute this block.
currentSum -= arr[i - (k-1)]; What is happening here?
Apologies in advance for the formatting, and thank you to all those answer.

if(i >= k - 1)
This check is to make sure the sum variable always has a sum of k elements.
If window size is k, then all good. Then size becomes k+1 when moving to next i. Now, sum has value of k+1 elements, so you remove the first element from last window from sum to make sum have again sum of k elements. See image below for more clarity for k = 3.
As you can see in the above picture, for every next window of size k, we have to remove previous window's first element which is done in currentSum -= arr[i - (k-1)];

Related

Farthest Smaller Element in an Array

In an unsorted positive integer array, how to find out the farthest smaller element on the right side of each element in most efficient way?
Ex:
Input: 6 3 1 8 2 9 7
Output: 2 2 -1 7 -1 7 -1
Explanation:
For 6, the smaller elements on it's right side are [3, 1, 2]. Since the last smallest element is 2, it's the most farthest from 6.
Like wise for others.
If no such number exists answer is "-1"
One idea is:
let us call the original array A
keep an array min[] of size n of which min[i] means the minimum value of the sub-array A[i..n-1]. Obviously, min[i] <= min[i+1].
now move from right to left on A. At every index i, do a binary search on min[i+1..n-1] to find the farthest smaller value.
Java code:
int[] A = { 6, 2, 3, 10, 1, 8 };
int n = A.length;
// calculate min
int[] min = new int[n];
min[n - 1] = A[n - 1];
for (int i = n - 2; i >= 0; i--)
min[i] = Math.min(A[i], min[i + 1]);
// calculate results
int[] results = new int[n];
results[n - 1] = -1;
for (int i = n - 2; i >= 0; i--) {
int left = i; // after the binary search, A[left] would be the answer
int right = n - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (min[mid] < A[i])
left = mid;
else
right = mid - 1;
if (min[left] < A[i])
results[i] = min[left];
else
results[i] = -1;
}
}
Space complexity O(n)
Time complexity O(nlogn) for all cases.
Compared to the solution from #vivek_23, the above algorithm would be better in the following worst case:
Imagine the case of A of n elements as follows
A = [ n/2 n/2 .. n/2 1 2 .. n/2]
If we use the stack solution suggested by #vivek_23,
at the step to find the farthest smaller element of any of the first n/2 elements (which are all valued n/2), st1 should be now [1 2 .. n/2]
for each element valued n/2, all st1 elements except n/2 will be transferred to st2 in order to find the farthest smaller element n/2 - 1. After that all elements in st2 will be transferred back to st1. This results in the worst case performance of O(n). As there are n/2 elements, the total worst time performance is O(n^2).
The basic idea behind the getting the answer quickly is to use a stack when moving from right to left in the array.
We insert an element in the stack only in one of the below 2 conditions,
If the stack is empty.
If the current top element in the stack is greater than the current element in iteration.
This would ensure us the correct results since a number greater than the current element in iteration will always be anyway greater than the current element at the top of the stack and current top at stack also wins over the farthest criteria.
So, insert in stack only if less than the current top.
However, it's quite possible that current element in iteration has many elements in stack smaller than itself. So, we need to go deep in stack till we find an element in stack greater than the current one.
Implementation(in java):
int[] arr = {6,3,1,8,2,9,7};
Stack<Integer> st1 = new Stack<Integer>();
Stack<Integer> st2 = new Stack<Integer>();
List<Integer> result = new ArrayList<>();
for(int i=arr.length-1;i>=0;--i){
while(!st1.isEmpty() && arr[(int)st1.peek()] < arr[i]){
st2.push(st1.pop());
}
if(st2.isEmpty()) result.add(-1);
else result.add(arr[(int)st2.peek()]);
while(!st2.isEmpty()) st1.push(st2.pop());
if(st1.isEmpty() || arr[(int)st1.peek()] > arr[i]){
st1.push(i);
}
}
The above implementation follows the explanation provided.
We use 2 stacks to not lose the popped data as it would be useful for future elements.
So, we revert all back to the main stack once the answer is found for the current element.
Demo: https://ideone.com/0oAasu
Note: You can directly store elements in the stack instead of indexes to make it more simpler.
Update: This solution's complexity is indeed O(n^2) for case where array could have elements in [ n/2, n/2 ,.. n/2, 1, 2, .. n/2] fashion for an array of size 10^5 or more. See Quynh Tran's answer for a better solution.
int arr[]={6,3,1,8,2,9,7};
for(int i=0;i<arr.length;i++){
int min=-1;
for(int j=i+1;j<arr.length;j++){
if(arr[j]<arr[i]){
min=arr[j];
}
}
arr[i]=min;
}

Given an unsorted integer array find numbers that are not searchable

Interview question from a friend
Given an unsorted integer array, how many number are not able to find using binary search?
For example, [2, 3, 4, 1, 5], only the number 1 can't be find using binary search, hence count = 1
[4,2,1,3,5] 4 and 4 and 2 are not searchable => binarySearch(arr, n) return a number that is not equal to num
Expected run time is O(n)
Can't think of an algorithm that can achieve O(n) time :(
Thought about building min and max arr, however, woudln't work as the subarray can mess it out again.
Already knew the O(nlogn) approach, it was obvious, just call binary search for each number and check.
I believe this code works fine. It does one single walk of each value in the list, so it is O(n).
function CountUnsearchable(list, minValue = -Infinity, maxValue=Infinity) {
if (list is empty) return 0;
let midPoint = mid point of "list"
let lowerCount = CountUnsearchable(left half of list, minValue, min(midPoint, maxValue));
let upperCount = CountUnsearchable(right half of list, max(minValue, midPoint), maxValue);
let midPointUnsearchable = 1 if midPoint less than minValue or greater than maxValue, otherwise 0;
return lowerCount + upperCount + midPointUnsearchable;
}
It works, because we walk the tree a bit like we would in a binary search, except at each node we take both paths, and simply track the maximum value that could have led us to take this path, and the minimum value that could have led us to take this path. That makes it simple to look at the current value and answer the question of whether it can be found via a binary search.
Try to create the following function:
def count_unsearchable(some_list, min_index=None, max_index=None, min_value=None, max_value=None):
"""How many elements of some_list are not searchable in the
range from min_index to max_index, assuming that by the time
we arrive our values are known to be in the range from
min_value to max_value. In all cases None means unbounded."""
pass #implementation TBD
It is possible to implement this function in a way that runs in time O(n). The reason why it is faster than the naive approach is that you are only making the recursive calls once per range, instead of once per element in that range.
Idea: Problem can be reworded as - find the count of numbers in the array which are greater than all numbers to their left and smaller than all numbers to their right. Further simplified, find the count of numbers which are greater than the max number to their left and smaller than the minimum number to their right.
Code: Java 11 | Time/Space: O(n)/O(n)
int binarySearchable(int[] nums) {
var n = nums.length;
var maxToLeft = new int[n + 1];
maxToLeft[0] = Integer.MIN_VALUE;
var minToRight = new int[n + 1];
minToRight[n] = Integer.MAX_VALUE;
for (var i = 1; i < n + 1; i++) {
maxToLeft[i] = Math.max(maxToLeft[i - 1], nums[i - 1]);
minToRight[n - i] = Math.min(minToRight[n + 1 - i], nums[n - i]);
}
for (var i = 0; i < n; i++)
if (nums[i] >= maxToLeft[i + 1] && nums[i] <= minToRight[i + 1])
count++;
return count;
}
TopCoder problem: https://community.topcoder.com/stat?c=problem_statement&pm=5869&rd=8078
Video explanation: https://www.youtube.com/watch?v=blICHR_ocDw
LeetCode discuss: https://leetcode.com/discuss/interview-question/352743/Google-or-Onsite-or-Guaranteed-Binary-Search-Numbers

Minimum difference between heights of Towers?

I was going through some interview questions, I saw this one
You are given the height of n towers and value k. You have to either increase or decrease the height of every tower by k. You need to minimize the difference between the height of the longest and the shortest tower and output this difference.
I think the answer will be (maxheight-k) - (minheight + k).
I have tried on some test cases it is running fine.
But I am not sure, I think I am missing something, Am I ?
m7thon's answer explains the problem with your solution, so I'll just explain how you can actually solve this . . .
The big thing to observe is that for any given tower, if you choose to increase its height from hi to hi + k, then you might as well increase the height of all shorter towers: that won't affect the maximum (because if hj < hi, then hj + k < hi + k), and may help by increasing the minimum. Conversely, if you choose to decrease the height of a tower from hi to hi − k, then you might as well decrease the heights of all taller towers.
So while there are 2n possible ways to choose which towers should be increased vs. decreased, we can actually ignore most of these. Some tower will be the tallest tower that we increase the height of; for all shorter towers, we will increase their height as well, and for all taller towers, we will decrease their height. So there are only n interesting ways to choose which towers should be increased vs. decreased: one for each tower's chance to be the tallest tower that we increase the height of.
[Pedantic note #1: You may notice that it's also valid to decrease the heights of all towers, in which case there's no such tower. But that's equivalent to increasing the heights of all towers — whether we add k to every height or subtract k from every height, either way we're not actually changing the max-minus-min.]
[Pedantic note #2: I've only mentioned "shorter towers" and "taller towers", but it's also possible that multiple towers have the same initial height. But this case isn't really important, because we might as well increase them all or decrease them all — there's no point increasing some and decreasing others. So the approach described here still works fine.]
So, let's start by sorting the original heights and numbering them in increasing order, so that h1 is the original height of the originally-shortest tower and hn is the original height of the originally-tallest tower.
For each i, try the possibility that the ith-shortest tower is the tallest tower that we increase the height of; that is, try the possibility that we increase h1 through hi and decrease hi+1 through hn. There are two groups of cases:
If i < n, then the final height of the finally-shortest tower is min(h1 + k, hi+1 − k), and the final height of the finally-tallest tower is max(hi + k, hn − k). The final difference in this case is the latter minus the former.
If i = n, then we've increased the heights of all towers equally, so the final difference is just hn − h1.
We then take the least difference from all n of these possibilities.
Here's a Java method that implements this (assuming int-valued heights; note that hi is arr[i-1] and hi+1 is arr[i]):
private static int doIt(final int[] arr, final int k) {
java.util.Arrays.sort(arr);
final int n = arr.length;
int result = arr[n - 1] - arr[0];
for (int i = 1; i < n; ++i) {
final int min = Math.min(arr[0] + k, arr[i] - k);
final int max = Math.max(arr[n - 1] - k, arr[i - 1] + k);
result = Math.min(result, max - min);
}
return result;
}
Note that I've pulled the i = n case before the loop, for convenience.
Lets say you have three towers of heights 1, 4 and 7, and k = 3. According to your reasoning the optimal minimum difference is (7 - 3) - (1 + 3) = 0. But what do you do with the tower of height 4? You either need to increase or decrease this, so the minimum difference you can achieve is in fact 3 in this example.
Even if you are allowed to keep a tower at its height, then the example 1, 5, 7 will disprove your hypothesis.
I know this does not solve the actual minimization problem, but it does show that it is not as simple as you thought. I hope this answers your question "Am I missing something?".
I assume this came from gfg.
The answer of #ruakh is perhaps the best I've found online, it'll work for most cases, but for the practice problem on gfg, there are a few cases which can cause the minimum to go below 0, and the question doesn't allow any height to be < 0.
So for that, you'll need an additional check, and the rest of it is pretty much entirely inspired from ruakh's answer
class Solution {
int getMinDiff(int[] arr, int n, int k) {
Arrays.sort(arr);
int ans = arr[n-1] - arr[0];
int smallest = arr[0] + k, largest = arr[n-1]-k;
for(int i = 0; i < n-1; i++){
int min = Math.min(smallest, arr[i+1]-k);
int max = Math.max(largest, arr[i]+k);
if(min < 0) continue;
ans = Math.min(ans, max-min);
}
return ans;
}
}
I also went in for 0-based indexing for the heights to make it more obvious, but maybe that's subjective.
Edit: One case where the < 0 check is important, is when the array is
8 1 5 4 7 5 7 9 4 6 and k is 5. The expected answer for this is 8, without the < 0 check, you'd get 7.
A bit late here. Already these guys have explained you the problem and given you the solution. However, I have prepared this code myself. The code I prepared is not the best code that you should follow but gives a clear understanding of what can be done to achieve this using brute-force.
set = list(map(int, input().split()))
k = int(input())
min = 999999999
for index in range(2**len(set)):
binary = [] //probably should have used integer to binary fuction here
while index != 0:
remainder = index % 2
index //= 2
binary.append(remainder)
while len(binary) != len(set):
binary.append(0)
binary.reverse()
separateset = []
flag = 0
for i in range(len(binary)):
if binary[i] == 0:
separateset.append(set[i]+k)
elif binary[i] == 1 and set[i]-k >= 0:
separateset.append(set[i]-k)
else:
flag = 1
break
if flag == 0:
separateset.sort()
if min > separateset[-1] - separateset[0]:
min = separateset[-1] - separateset[0]
print(min)
This is achieved by identifying all the possible subsets of the set variable but with just some modifications. If the digit is 0, the value at that i (index not the index in the for loop) in the set is added with k otherwise if the digit is 1 and set[i]-k >= 0, the value at that index in the set is subtracted by k (Now you can add or subtract k vice-versa, it doesn't matter until you get all possible combinations of +k and -k). set[i]-k >= 0 is to be followed because a negative height wouldn't make sense and if that happens, flag becomes 1 and breaks. But if the flag is 0, it means that all the heights are positive and then the separatesort is sorted and then min stores the difference between the largest and shortest tower. This min ultimately has the minimum of all the differences.
Step 1 :
Decrease all the heights by 'k' and sort them in non-decreasing order.
Step 2 :
We need to increase some subset of heights by '2 * k' (as they were decreased by
'k' in step1, so, to effectively increase their heights by 'k' we need
to add '2*k') .
Step 3 :
Clearly if we increase the 'i'th height without increasing the
'i-1'th then, it will not be useful as the minimum is still the same
and maximum may also increase !
Step 4 :
Consider all prefixes with '2*k' added to each element of the prefix .
Then calculate and update the (max - min) value.
Let me know which scenario am I missing here,
class Solution:
def getMinDiff(self, arr, n, k):
for i in range(n):
if arr[i] < k: arr[i] += k
else: arr[i] -= k
result = max(arr) - min(arr)
print('NewArr: {}\nresult: {}'.format(arr, result))
return result
C++ code :
int getMinDiff(int arr[], int n, int k) {
// code here
sort(arr , arr+n);
int result = arr[n - 1] - arr[0];
for (int i = 1; i < n; ++i) {
int min_ = min(arr[0] + k, arr[i] - k);
int max_ = max(arr[n - 1] - k, arr[i - 1] + k);
result = min(result, max_ - min_);
}
return result;
}
First you are gonna need to find average height of the towers.
lets say heights are 3, 7, 17, 25, 45 and k = 5
the average will be = ( 3 + 7 + 17 + 25 + 45 ) / 5 = 97 / 5 = 19.4
Now we will try to make every building closer to average height.
for 3 height tower we have to add 5 three times making height = 3 + (3*5) = 18 (18 is closer than 23) close to average.
for 7 height we will add 5 two times = 7 + (2 *5) = 17 (17 is closer than 22)
Similarly 25 will become 25 - 5 = 20
and 45 will become 45 - (5 *5) = 20
your height will becomes 18, 17, 17, 20, 20
This approach works on GfG practice, Problem link: https://practice.geeksforgeeks.org/problems/minimize-the-heights/0/
Approach :
Find max, min element from the array. O(n). Take the average, avg = (max_element + min_element)/2.
Iterate over the array again, and for each element, check if it is less than avg or greater.
If the current element arr[i] is less than avg, then add "k" to a[i], i.e a[i] = a[i] + k.
If the current element arr[i] is greater than or equal to avg, then subtract k from a[i], i.e a[i] = a[i] - k;
Find out the minimum and maximum element again from the modified array.
Return the min(max1-min1, max2-min2), where (max1, min1) = max and min elements initially before the array was modified, and (max2, min2) are the max and min elements after doing modification.
Entire Code can be found here: https://ide.geeksforgeeks.org/56qHOM0EOA

Explanation for chained Matrix Multiplication using DP?

I could not understand the optimised chained Matrix multiplication(using DP) code example given in my algorithm's book.
int MatrixChainOrder(int p[], int n)
{
/* For simplicity of the program, one extra row and one extra column are
allocated in m[][]. 0th row and 0th column of m[][] are not used */
int m[n][n];
int i, j, k, L, q;
/* m[i,j] = Minimum number of scalar multiplications needed to compute
the matrix A[i]A[i+1]...A[j] = A[i..j] where dimention of A[i] is
p[i-1] x p[i] */
// cost is zero when multiplying one matrix.
for (i = 1; i < n; i++)
m[i][i] = 0;
// L is chain length.
for (L=2; L<n; L++)
{
for (i=1; i<=n-L+1; i++)
{
j = i+L-1;
m[i][j] = INT_MAX;
for (k=i; k<=j-1; k++)
{
// q = cost/scalar multiplications
q = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if (q < m[i][j])
m[i][j] = q;
}
}
}
return m[1][n-1];
}
Why does the first loop starts from 2 ?
Why is j set to i+L-1 and i to n-L+1 ?
I understood the recurrence relation, but could not understand why loops are set like this ?
EDIT:
What is the way to get the parenthesis order after DP ?
In bottom up, that is DP we try to solve the smallest possible case first(we solve each smallest case). Now when we look at the recurrence (m[i,j] represents cost to parenthise from i , j..)
We can see that the smallest possible solution(which will be needed by any other larger sub problem) is of a smaller length than that we need to solve... For P(n) .We need all the costs of parenthising the expression with length lessser than n. This leads us to solve the problem lengthwise... (Note l in the outer loop represents length of the segment whose cost we are trying to optimise)
Now first we solve all the sub problems of length 1 i.e. 0 always (No multiplication required)...
Now your question L=2 -> L=n
we are varying length from 2 to n just to solve the sub problems in order...
i is the starting point of all the sub intervals such that they can be the begining of an interval of length l..
Naturally j represents the end of sub interval -> i+l-1 is the end of sub interval (just because we know the starting point and length we can figure out the end of subinterval)
L iterates the length of a chain. Clearly, a chain cannot be 1 piece long. i iterates the beginning of the chain. If the first piece is i, then the last piece will be i+L-1, which is j. (Try to imagine a chain and count). The condition in the cycle makes sure that for any value of i, the last piece is not greater than the maximum Length n.
Shortly, those are limitations to keep the values in the given boundaries.

Given an array of size N I need to find the min number of values that will sum up within a min and max range

Given an array of size N I need to find the min number of values that will sum up within a min and max range.
E.g.: consider an array[ 1,2,3,4,5 ]. I need to find min number of values from this array whose sum is greater than 5 and less than 8.
Ans: since 1+5 is greater than 5 and less than 8 so the min number of values is 2 hence the answer.
And below is my function which implements the logic.
int void CheckValue()
{
for (i = 0; i <5; i++)
if (a[i] > min && a[i] < max)
return 1;
for (i = 0; i< 4; i++)
for (j = i + 1; j < 5; j++)
if (a[i] + a[j] > min && a[i] + a[j] < max)
return 2;
for (i = 0; i < 3; i++)
for (j = i + 1; j < 4; j++)
for (k = j+1; k < 5; k++)
if (a[i] + a[j] + a[k] > min && a[i] + a[j] + a[k] < max)
return 3;
for (i = 0; i < 2; i++)
for (j = i + 1; j< 3; j++)
for (k = j + 1; k< 4; k++)
for (l = k + 1; l < 5; l++)
if (a[i] + a[j] + a[k] + a[l] > min && a[i] + a[j] + a[k] + a[l] < max)
return 4;
if(a[0]+a[1]+a[2]+a[3]+a[4]>min && a[0]+a[1]+a[2]+a[3]+a[4]<max)
return 5;
return 0;
}
It works fine but the problem is its complexity. Can anyone provide any suggestions to optimize this code further or provide a better logic to implement this.
I don't have any experience with this kind of things so it is probable that there are better ways of doing it, but I do have some insights that may be helpful.
Currently you are calculating every possible combination, you should be able to alter your algorithm to make it so that you can eliminate some combinations without having to calculate them.
I would sort the array to begin with, that will let you eliminate some values without calculating them.
For instance if you have an array that looks like [1,2,4,5,9] and the min=11 and max=14 then your algorithm will check 1+2,1+4,1+5,1+9 then 2+4, 2+5, 2+9, 4+5, 4+9 before coming to an answer.
If instead you start with the highest number first you can eliminate all possible 1 combinations by doing the calculation 9+1, since 9+1<=11 it must be the case that all other possible 1 combinations are invalid for the two number sum, the same with all possible 2 combinations. If you add logic like this to your code you should have less superfluous calculations, hopefully speeding your code up.
Is this a homework question?
Your question is really not clear but here is what i would :
Sort it. nlogn.
Start with adding the first element and last element. Is that in the range?
Take the first pointer from one end, lets say from beginning, move it to middle and add the middle number and the last number, first pointer + last pointer.
is that in the range? you can move the first pointer to the middle between first and last pointer, ie: right by 3/4 of the sequence.
So you are using binary search here with two pointers on a sorted sequence.
This will give you an estimate number of elements, which will be in range. I hope you got the idea.
You can move the second pointer to middle, if your sum is out of range.
This will give you nlogn.
Please note that this is just for two numbers, i m not sure if you are asking for all possible numbers whose addition would be in the range or only two numbers?
two numbers is easy, nlogn does it
All possible subset is subset sum problem which is np hard. exponential which is 2**n.
This is a rather complex problem, likely to be np hard.
One thing that comes to mind is that it slightly resembles the 'knapsack problem'. Perhaps you can find an implementation of that and adapt it.
If the minimum amount of items is expected to be small, you can of course use a brute force approach:
Set minVal = 1
Find all sets of size minVal
As long as none of the sets meet your criteria, add 1 to minVal and go to step 2
I would propose the following solution:
Lets say the minimum value of range is minVal and maximum value is maxVal.
Now sort the array.Lets say the length of array is len
Do a binary search for number in array which is just <= maxVal.
Search pass:
I mean if number is at index i then number at index i+1 should be >=maxVal. Lets say the index of this number is currIndex.
If this number is equal to maxVal then do binary search between 0 to currIndex for number
minVal and
Search Fail:
This mean highest number is array is less than the maxVal. So for this case follow the steps below:
1) Add the largest number in array to the result set.
2)Now start loop from len-1 t0 1. if arr[len-1] + arr[len] is less that maxVal then add arr[len-1] to result set and continue the loop. If arr[len-1] + arr[len] > maxVal then skip and check for arr[len-1] + arr[len].
and so on.
I think you should consider sorting your array, there are many efficient algoritms for this.
Then start from the biggest value and cummulatively add smaller values in sorted order, checking the condition at each step.

Resources