Water collected between towers

后端 未结 26 997
无人共我
无人共我 2020-12-22 16:51

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

相关标签:
26条回答
  • 2020-12-22 17:36

    O(n) solution in Java, single pass

    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.

    1. Find the first "peak" by looping through the list until the tower height stops increasing. All water before this will not be collected (drain off to the left).
    2. For all subsequent towers:
      • If the height of the subsequent tower decreases or stays the same, add water to a "potential collection" bucket, equal to the difference between the tower height and the previous max tower height.
      • If the height of the subsequent tower increases, we collect water from the previous bucket (subtract from the "potential collection" bucket and add to the collected bucket) and also add water to the potential bucket equal to the difference between the tower height and the previous max tower height.
      • If we find a new max tower, then all the "potential water" is moved into the collected bucket and this becomes the new max tower height.

    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;
    }
    
    0 讨论(0)
  • 2020-12-22 17:38

    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;
    }
    
    0 讨论(0)
提交回复
热议问题