I recently came across an interview question asked by Amazon and I am not able to find an optimized algorithm to solve this question:
You are given an input array wh
Another implementation in Java, finding the water collected in a single pass through the list. I scanned the other answers but didn't see any that were obviously using my solution.
In the example above, with input: [5,3,7,2,6,4,5,9,1,2], the solution works as follows:
- 5: Finds 5 as the first peak
- 3: Adds 2 to the potential bucket (5-3)
collected = 0, potential = 2
- 7: New max, moves all potential water to the collected bucket
collected = 2, potential = 0
- 2: Adds 5 to the potential bucket (7-2)
collected = 2, potential = 5
- 6: Moves 4 to the collected bucket and adds 1 to the potential bucket (6-2, 7-6)
collected = 6, potential = 2
- 4: Adds 2 to the potential bucket (6-4)
collected = 6, potential = 4
- 5: Moves 1 to the collected bucket and adds 2 to the potential bucket (5-4, 7-5)
collected = 7, potential = 6
- 9: New max, moves all potential water to the collected bucket
collected = 13, potential = 0
- 1: Adds 8 to the potential bucket (9-1)
collected = 13, potential = 8
- 2: Moves 1 to the collected bucket and adds 7 to the potential bucket (2-1, 9-2)
collected = 14, potential = 15
After running through the list once, collected water has been measured.
public static int answer(int[] list) {
int maxHeight = 0;
int previousHeight = 0;
int previousHeightIndex = 0;
int coll = 0;
int temp = 0;
// find the first peak (all water before will not be collected)
while(list[previousHeightIndex] > maxHeight) {
maxHeight = list[previousHeightIndex];
previousHeightIndex++;
if(previousHeightIndex==list.length) // in case of stairs (no water collected)
return coll;
else
previousHeight = list[previousHeightIndex];
}
for(int i = previousHeightIndex; i<list.length; i++) {
if(list[i] >= maxHeight) { // collect all temp water
coll += temp;
temp = 0;
maxHeight = list[i]; // new max height
}
else {
temp += maxHeight - list[i];
if(list[i] > previousHeight) { // we went up... collect some water
int collWater = (i-previousHeightIndex)*(list[i]-previousHeight);
coll += collWater;
temp -= collWater;
}
}
// previousHeight only changes if consecutive towers are not same height
if(list[i] != previousHeight) {
previousHeight = list[i];
previousHeightIndex = i;
}
}
return coll;
}
Here is a solution in JAVA that traverses the list of numbers once. So the worst case time is O(n). (At least that's how I understand it).
For a given reference number keep looking for a number which is greater or equal to the reference number. Keep a count of numbers that was traversed in doing so and store all those numbers in a list.
The idea is this. If there are 5 numbers between 6 and 9, and all the five numbers are 0's, it means that a total of 30 units of water can be stored between 6 and 9. For a real situation where the numbers in between aren't 0's, we just deduct the total sum of the numbers in between from the total amount if those numbers were 0. (In this case, we deduct from 30). And that will give the count of water stored in between these two towers. We then save this amount in a variable called totalWaterRetained and then start from the next tower after 9 and keep doing the same till the last element.
Adding all the instances of totalWaterRetained will give us the final answer.
JAVA Solution: (Tested on a few inputs. Might be not 100% correct)
private static int solveLineTowerProblem(int[] inputArray) {
int totalWaterContained = 0;
int index;
int currentIndex = 0;
int countInBetween = 0;
List<Integer> integerList = new ArrayList<Integer>();
if (inputArray.length < 3) {
return totalWaterContained;
} else {
for (index = 1; index < inputArray.length - 1;) {
countInBetween = 0;
integerList.clear();
int tempIndex = index;
boolean flag = false;
while (inputArray[currentIndex] > inputArray[tempIndex] && tempIndex < inputArray.length - 1) {
integerList.add(inputArray[tempIndex]);
tempIndex++;
countInBetween++;
flag = true;
}
if (flag) {
integerList.add(inputArray[index + countInBetween]);
integerList.add(inputArray[index - 1]);
int differnceBetweenHighest = min(integerList.get(integerList.size() - 2),
integerList.get(integerList.size() - 1));
int totalCapacity = differnceBetweenHighest * countInBetween;
totalWaterContained += totalCapacity - sum(integerList);
}
index += countInBetween + 1;
currentIndex = index - 1;
}
}
return totalWaterContained;
}