# Arrays 1: One Dimensional
## Problem 1 Find Maximum Subarray Sum
### Problem Statement
Given an integer array A, find the maximum subarray sum out of all the subarrays.
### Examples
**Example 1**:
For the given array A with length N,
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|:-----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| Array | -2 | 3 | 4 | -1 | 5 | -10 | 7 |
**Output:**
```plaintext
Max Sum: 11
Subarray: 3 4 -1 5
```
**Example 2:**
For the given array A with it's length as N we have,
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|:-----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| Array | -3 | 4 | 6 | 8 | -10 | 2 | 7 |
**Output:**
```plaintext
Max Sum: 18
Subarray: 4 6 8
```
---
### Question
For the given array A, what is the maximum subarray sum ?
A[ ] = { 4, 5, 2, 1, 6 }
**Choices**
- [ ] 6
- [x] 18
- [ ] No Idea
- [ ] 10
```plaintext
Max Sum: 18
Subarray: 4 5 2 1 6
```
### Question
For the given array A, what is the maximum subarray sum ?
A[ ] = { -4, -3, -6, -9, -2 }
**Choices**
- [ ] -9
- [ ] 18
- [x] -2
- [ ] -24
```plaintext
Max Sum: -2
Subarray: -2
```
---
### Find Maximum Subarray Sum Brute Force
#### Brute Force
No of possible subarrays: `N * (N + 1) / 2`
Iterate over all subarrays, calculate sum and maintain the maximum sum.
#### Psuedocode:
```java
ans = A[0];
for (i = 0; i < N; i++) { // start to N
for (j = i; j < N; j++) { // end
for (k = i; k <= j; k++) {
sum += A[k];
}
ans = Math.max(ans, sum);
sum = 0; // Reset sum for the next iteration
}
}
return ans;
```
#### Complexity
**Time Complexity:** `O(N^2 * N) = O(N^3)`
**Space Complexity:** `O(1)`
:::warning
Please take some time to think about the optimised approach on your own before reading further.....
:::
---
### Find Maximum Subarray Sum using Carry Forward
#### Optimized Solution using Carry Forward
We don't really need the third loop present in brute force, we can optimise it further using Carry Forward technique.
#### Psuedocode
```java
ans = A[0]
for (i = 0 to N - 1) { //start to N
sum = 0
for (j = i to N - 1) { //end
sum += A[k]
ans = max(ans, sum)
}
}
return ans;
```
#### Complexity
**Time Complexity:** O(N^2)
**Space Complexity:** O(1)
---
### Find Maximum Subarray Sum using Kadanes Algorithm
#### Observation:
**Case 1:**
If all the elements in the array are positive
Arr[] = `[4, 2, 1, 6, 7]`
**Answer:**
To find the maximum subarray we will now add all the positive elements
Ans: `(4 + 2 + 1 + 6 + 7) = 20`
**Case 2:**
If all the elements in the array are negative
Arr[] = `[-4, -8, -9, -3, -5]`
**Answer:**
Here, since a subarray should contain at least one element, the max subarray would be the element with the max value
Ans: `-3`
**Case 3:**
If positives are present in between
Arr[] = [-ve -ve -ve `+ve +ve +ve +ve` -ve -ve -ve]
**Answer:**
Here max sum would be the sum of all positive numbers
**Case 4:**
If all negatives are present either on left side or right side.
Arr[ ] = [-ve -ve -ve `+ve +ve +ve +ve`]
OR
Arr[ ] = [`+ve +ve +ve +ve` -ve -ve -ve -ve]
**Answer:**
All postives on sides
Case 5 :
**Hint:**
What if it's some ve+ followed by some ve- and then again some more positives...
```plaintext
+ve +ve +ve -ve -ve -ve +ve +ve +ve +ve +ve
```
#### Solution:
We will take all positives, then we consider negatives only if the overall sum is positive because in the future if positives come, they may further increase this positivity(sum).
**Example** -
```plaintext
A[ ] = { -2, 3, 4, -1, 5, -10, 7 }
```
Answer array: 3, 4, -1, 5
**Explanation**:
3+4 = 7
7 + (-1) = 6 (still positive)
6+5 = 11 (higher than 7)
#### Dry Run
```plaintext
0 1 2 3 4 5 6 7 8
{ -20, 10, -20, -12, 6, 5, -3, 8, -2 }
```
| i | currSum | maxSum | |
|:---:|:-------:|:------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| 0 | -20 | -20 | reset the currSum to 0 and do not propagate since adding a negative will make it more negative and adding a positive will reduce positivity of that element. |
currSum = 0
| i | currSum | maxSum | |
|:---:|:-------------:|:------:|:------------------:|
| 1 | 10 | 10 | |
| 2 | 10 + (-20)= -10 | 10 | reset currSum to 0 |
currSum = 0
| i | currSum | maxSum | |
|:---:|:-------:|:------:|:------------------:|
| 3 | -12 | 10 | reset currSum to 0 |
currSum = 0
| i | currSum | maxSum | |
|:---:|:---------:|:------:|:---------------------------------------------------------------------------:|
| 4 | 6 | 10 | |
| 5 | 6 + 5 | 11 | |
| 6 | 6 + 5 - 3 = 8 | 11 | Keep currSum as 8 only since if we find a positive, it can increase the sum |
| i | currSum | maxSum | |
|:---:|:-------:|:------:| --------------------------------------------------------------------------- |
| 7 | 8 + 8 = 16 | 16 | |
| 8 | 16 - 2 = 14 | 16 | Keep currSum as 8 only since if we find a positive, it can increase the sum |
Final maxSum = 16
---
### Question
Tell the output of the below example after running the Kadane's Algorithm on that example
A[ ] = { -2, 3, 4, -1, 5, -10, 7 }
**Choices**
- [ ] 9
- [ ] 7
- [x] 11
- [ ] 0
---
### Find Maximum Subarray Sum Kadanes Pseudocode
#### Pseudocode
```cpp
int maximumSubarraySum(int[] arr, int n) {
int maxSum = Integer.MIN_VALUE, currSum = 0;
for (int i = 0; i <= n - 1; i++) {
currSum += arr[i];
if (currSum > maxSum) {
maxSum = currSum;
}
if (currSum < 0) {
currSum = 0;
}
}
return maxSum;
}
```
#### Complexity
**Time Complexity:** O(n)
**Space Complexity:** O(1)
The optimized method that we just discussed comes under **Kadane's Algorithm** for solving maximum subarray problem
---
### Problem 2 Perform multiple Queries from i to last index
#### Problem Statement
Given an integer array A where every element is 0, return the final array after performing multiple queries
**Query (i, x):** Add x to all the numbers from index i to N-1
**Example**
Let's say we have a zero-filled array of size 7 with the following queries:
Query(1, 3)
Query(4, -2)
Query(3, 1)
Let's perform these queries and see how it works out.
**Example Explanation**
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| ----- | --- | --- | --- | --- | --- | --- | ----- |
| **Array** | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| **Q1** | : | +3 | +3 | +3 | +3 | +3 | +3|
| **Q2** | : | : | : | : | -2 | -2 | -2|
| **Q3** | : | : | : | +1 | +1 | +1 | +1
| **Ans[]** | 0 | 3 | 3 | 4 | 2 | 2 | 2 |
---
### Question
Return the final array after performing the queries
**Note:**
- **Query (i, x):** Add x to all the numbers from index i to N-1
- 0-based Indexing
```cpp
A = [0, 0, 0, 0, 0]
Query(1, 3)
Query(0, 2)
Query(4, 1)
```
**Choices**
- [ ] [6, 6, 6, 6, 6]
- [x] [2, 5, 5, 5, 6]
- [ ] [2, 3, 3, 3, 1]
- [ ] [2, 2, 5, 5, 6]
---
#### Explanation
| Index | 0 | 1 | 2 | 3 | 4 |
| ----- | --- | --- | --- | --- | --- |
| **Array** | 0 | 0 | 0 | 0 | 0 |
| **Q1** | : | +3 | +3 | +3 | +3 |
| **Q2** | +2 | +2 | +2 | +2 | +2 |
| **Q3** | : | : | : | : | +1 |
| **Ans[]** | 2 | 5 | 5 | 5 | 6 |
---
### Perform multiple Queries from i to last index Solution Approaches
#### Brute force Approach
One way to approach this question is for a given number of Q queries, we can traverse the entire array each time.
#### Complexity
**Time Complexity:** O(Q * N)
**Space Complexity:** O(1)
#### Optimized Solution
#### Hint:
* Wherever we're adding the value initially, the value is to be carried forward to the very last of the array isn't it?
* Which is the concept that helps us carry forward the sum to indices on right hand side ?
Expected: **Prefix Sum!**
* Idea is that first we add the values at the ith indices as per given queries.
* Then, at the end, we can propagate those sum to indices on right.
* This way, we're only iterating over the array once unlike before.
#### Dry Run
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| --------- | --- | --- | --- | --- | --- | --- | --- |
| **Array** | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| **Q1** | : | +3 | : | : | : | : | : |
| **Q2** | : | : | : | : | +2 | : | |
| **Q3** | : | : | : | +1 | : | : | : |
| **Ans[]** | 0 | 3 | 0 | 1 | 2 | 0 | 0 |
| **psum[]** | 0 | 3 | 3 | 4 | 6 | 6 | 6 |
#### Pseudocode
```cpp
for (i = 0; i < Q.length; i++) {
index = B[i][0];
val = B[i][1];
A[index] += val;
}
for (i = 1; i < N; i++) {
A[i] += A[i - 1];
}
return A;
```
#### Complexity
**Time Complexity:** O(Q + N)
**Space Complexity:** O(1) since we are only making changes to the answer array that needs to be returned.
---
### Problem 3 Perform multiple Queries from index i to j
#### Problem Statement
Given an integer array A such that all the elements in the array are 0. Return the final array after performing multiple queries
`Query: (i, j, x)`: Add x to all the elements from index i to j
Given that `i <= j`
**Examples**
Let's take an example, say we have the zero-filled array of size 7 and the queries are given as
q1 = (1, 3, 2)
q2 = (2, 5, 3)
q3 = (5, 6, -1)
---
### Question
Find the final array after performing the given queries on array of size **8**.
|i | j | x |
|- | - | - |
| 1 | 4 | 3 |
| 0 | 5 |-1 |
| 2 | 2 | 4 |
| 4 | 6 | 3 |
**Choices**
- [ ] 1 2 6 3 5 2 3 0
- [ ] -1 2 6 2 5 2 3 3
- [x] -1 2 6 2 5 2 3 0
- [ ] 1 2 6 3 5 2 0 3
---
#### Observations
In the provided query format `Query: (i, j, x)`
here, start (i) and end (j) are specifiying a range wherein the values (x) needs to be added to the elements of the given array
#### Brute force Solution Approach
In this solution we can iterate through the array for every query provided to us and perform the necessary operation over it.
#### Dry Run
The provided queries we have are
q1 = (1, 3, 2)
q2 = (2, 5, 3)
q3 = (5, 6, -1)
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| ------ | --- | --- | --- | --- | --- | --- | --- |
| Arr[7] | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| V1 | | 2 | 2 | 2 | | | |
| V2 | | | 3 | 3 | 3 | 3 | |
| V3 | | | | | | -1 | -1 |
| Ans | 0 | 2 | 5 | 5 | 3 | 2 | -1 |
#### Complexity
**Time Complexity:** O(Q * N)
**Space Complexity:** O(1)
#### Optimized Solution
* This time, wherever we're adding the value initially, the value is to be carried forward only till a particular index, right?
* Can we use the Prefix Sum concept here are well ?
* How can we make sure that the value only gets added up till index j ?
* What can help us negate the effect of **+val** ?
#### Idea
* We can add the value at the starting index and subtract the same value just after the ending index which will help us to only carry the effect of **+val** till a specific index.
* From the index(k) where we have done **-val**, the effect will neutralise i.e, from (k to N-1)
#### Pseudocode:
```cpp
zeroQ(int N, int start[], int end[], int val[]) {
long arr[N] = 0;
for (int i = 0; i < Q; i++) {
//ith query information: start[i], end[i], val[i]
int s = start[i], e = end[i], v = val[i];
arr[s] = arr[s] + v;
if (e < n - 1) {
arr[e + 1] = arr[e + 1] - v;
}
}
//Apply cumm sum a psum[] on arr
for (i = 1; i < N; i++) {
arr[i] += arr[i - 1];
}
return arr;
}
```
#### Complexity
**Time Complexity:** O(Q + N)
**Space Complexity:** O(1)
**Problem Statement**
Given N buildings with height of each building, find the rain water trapped between the buildings.
#### Example Explanation
Example:
arr[] = {2, 1, 3, 2, 1, 2, 4, 3, 2, 1, 3, 1}
We now need to find the rainwater trapped between the buildings
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/063/100/original/rain_trap.png?1706008133" width=600/>
**Ans: 8**
#### Hint:
If we get units of water stored over every building, then we can get the overall water by summing individual answers.
#### Observations
1. How much water is stored over **building 2** ? **-> 4 units**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/138/original/upload_1e8c00eedae54cb6b93c3d87945d152a.png?1695374556" width=300 />
2. Now, how much water is stored over **building 2** ? **still -> 4 units**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/139/original/upload_48646dcd1fd44599afb23abe521026c8.png?1695374587" width=300 />
3. Now, how much water is stored over **building 2** ? **still -> 4 units**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/140/original/upload_b6c255326a25dc18d22e80c225b962ab.png?1695374617" width=300 />
4. Now, how much water is stored over **building 2** ? **Now it is 6**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/141/original/upload_3faddfa43fec2bdff4817ab567b236c3.png?1695374641" width=300 />
5. Now, how much water is stored over **building 2** ? **Now it is 8**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/142/original/upload_78cd8d3521ef7b1141f700a6a4947945.png?1695374662" width=300 />
#### Conclusion:
It depends on the height of the minimum of the largest buildings on either sides.
**Example:**
Water stored over building 5 depends on minimum of the largest building on either sides.
**i.e, min(10, 12) = 10**
**Water stored over 5 is 10 - 5 = 5 units.**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/143/original/upload_1a3b70b3067fb4fd72a1240dae787f62.png?1695374697" width=300 />
---
### Question
Given N buildings with height of each building, find the rain water trapped between the buildings.
`A = [1, 2, 3, 2, 1]`
**Choices**
- [ ] 2
- [ ] 9
- [x] 0
- [ ] 3
**Explanation:**
No water is trapped, Since the building is like a mountain.
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/060/323/original/imageee.png?1703834723" width=300 />
:::warning
Please take some time to think about the solution approach on your own before reading further.....
:::
---
### Rain Water Trapping Brute Force Approach
For **ith** building,
We need to find maximum heights on both the left and right sides of **ith** building.
NOTE: For **0th** and **(N-1)th** building, no water will be stored on top.
#### Pseudocode (Wrong)
```cpp
ans = 0
for (int i = 1; i < N - 1; i++) {
maxL = max(0 to i - 1); //loop O(N)
maxR = max(i + 1 to N - 1); //loop O(N)
water = min(maxL, maxR) - A[i];
ans += water;
}
```
#### Edge Case
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/144/original/upload_fed83d7b202f6c0959ad932d3d5234f2.png?1695374778)" width=500 />
For building with height 4, the Lmax = 3 and Rmax = 3
min(3, 3) = 3
water = **3 - 4 < 0**
So, for such case, we'll take water stored as 0.
#### Pseudocode (Correct)
```cpp
ans = 0
for (int i = 1; i < N - 1; i++) {
maxL = max(0 to i - 1); //loop O(N)
maxR = max(i + 1 to N - 1); //loop O(N)
water = min(maxL, maxR) - A[i];
if (water > 0) {
ans += water;
}
}
```
#### Complexity
**Time Complexity:** O(N^2) {Since for every element, we'll loop to find max on left and right}
**Space Complexity:** O(N)
---
### Rain Water Trapping Optimised Approach
We can store the max on right & left using carry forward approach.
* We can take 2 arrays, lmax[] & rmax[].
* Below is the calculation for finding max on left & right using carry forward approach.
* This way, we don't have to find max for every element, as it has been pre-calculated.
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/145/original/upload_f948bda6a2057500be48a7c0fd0d5da7.png?1695374834" width=500 />
#### Pseudocode
```cpp
ans = 0;
int lmax[N] = {
0
};
for (int i = 1; i < N; i++) {
lmax[i] = max(lmax[i - 1], A[i - 1]);
}
int rmax[N] = {
0
};
for (int i = N - 2; i >= 0; i--) {
rmax[i] = max(rmax[i + 1], A[i + 1]);
}
for (int i = 1; i < N - 1; i++) {
water = min(lmax[i], rmax[i]) - A[i];
if (water > 0) {
ans += water;
}
}
```
#### Complexity
**Time Complexity:** O(N) {Since we have precalculated lmax & rmax}
**Space Complexity:** O(N)