Water collected between towers

后端 未结 26 993
无人共我
无人共我 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:11

    Readable Python Solution:

    def water_collected(heights):
        water_collected = 0
        left_height = []
        right_height = []
    
        temp_max = heights[0]
        for height in heights:
            if (height > temp_max):
                temp_max = height
            left_height.append(temp_max)
    
        temp_max = heights[-1]
        for height in reversed(heights):
            if (height > temp_max):
                temp_max = height
            right_height.insert(0, temp_max)
    
        for i, height in enumerate(heights):
            water_collected += min(left_height[i], right_height[i]) - height
        return water_collected
    
    0 讨论(0)
  • 2020-12-22 17:13

    You can do this by scanning the array twice.

    The first time you scan from top to bottom and store the value of the tallest tower you have yet to encounter when reaching each row.

    You then repeat the process, but in reverse. You start from the bottom and work towards the top of the array. You keep track of the tallest tower you have seen so far and compare the height of it to the value for that tower in the other result set.

    Take the difference between the lesser of these two values (the shortest of the tallest two towers surrounding the current tower, subtract the height of the tower and add that amount to the total amount of water.

    int maxValue = 0;
    int total = 0;
    int[n] lookAhead
    
    for(i=0;i<n;i++)
    {
        if(input[i] > maxValue) maxValue = input[i];
        lookahead[i] = maxValue;
    }
    
    maxValue = 0;
    for(i=n-1;i>=0;i--)
    {
        // If the input is greater than or equal to the max, all water escapes.
        if(input[i] >= maxValue)
        { 
            maxValue = input[i];
        }
        else
        {
            if(maxValue > lookAhead[i])
            {
                // Make sure we don't run off the other side.
                if(lookAhead[i] > input[i])
                {
                    total += lookAhead[i] - input[i];
                }
            }
            else
            {
                total += maxValue - input[i];
            }
        } 
    }
    
    0 讨论(0)
  • 2020-12-22 17:15

    Here is one more solution written on Scala

    def find(a: Array[Int]): Int = {
      var count, left, right = 0
    
      while (left < a.length - 1) {
        right = a.length - 1
        for (j <- a.length - 1 until left by -1) {
          if (a(j) > a(right)) right = j
        }
    
        if (right - left > 1) {
          for (k <- left + 1 until right) count += math.min(a(left), a(right)) - a(k)
          left = right
        } else left += 1
      }
    
      count
    }
    
    0 讨论(0)
  • 2020-12-22 17:16

    Once the water's done falling, each position will fill to a level equal to the smaller of the highest tower to the left and the highest tower to the right.

    Find, by a rightward scan, the highest tower to the left of each position. Then find, by a leftward scan, the highest tower to the right of each position. Then take the minimum at each position and add them all up.

    Something like this ought to work:

    int tow[N]; // nonnegative tower heights
    int hl[N] = {0}, hr[N] = {0}; // highest-left and highest-right
    for (int i = 0; i < n; i++) hl[i] = max(tow[i], (i!=0)?hl[i-1]:0);
    for (int i = n-1; i >= 0; i--) hr[i] = max(tow[i],i<(n-1) ? hr[i+1]:0);
    int ans = 0;
    for (int i = 0; i < n; i++) ans += min(hl[i], hr[i]) - tow[i];
    
    0 讨论(0)
  • 2020-12-22 17:16

    Here is a solution in Groovy in two passes.

    assert waterCollected([1, 5, 3, 7, 2]) == 2
    assert waterCollected([5, 3, 7, 2, 6, 4, 5, 9, 1, 2]) == 14
    assert waterCollected([5, 5, 5, 5]) == 0
    assert waterCollected([5, 6, 7, 8]) == 0
    assert waterCollected([8, 7, 7, 6]) == 0
    assert waterCollected([6, 7, 10, 7, 6]) == 0
    
    def waterCollected(towers) {
        int size = towers.size()
        if (size < 3) return 0
    
        int left = towers[0]
        int right = towers[towers.size() - 1]
    
        def highestToTheLeft = []
        def highestToTheRight = [null] * size
    
        for (int i = 1; i < size; i++) {
    
            // Track highest tower to the left
            if (towers[i] < left) {
                highestToTheLeft[i] = left
            } else {
                left = towers[i]
            }
    
            // Track highest tower to the right
            if (towers[size - 1 - i] < right) {
                highestToTheRight[size - 1 - i] = right
            } else {
                right = towers[size - 1 - i]
            }
        }
    
        int water = 0
        for (int i = 0; i < size; i++) {
            if (highestToTheLeft[i] && highestToTheRight[i]) {
                int minHighest = highestToTheLeft[i] < highestToTheRight[i] ? highestToTheLeft[i] : highestToTheRight[i]
                water += minHighest - towers[i]
            }
        }
    
        return water
    }
    

    Here same snippet with an online compiler: https://groovy-playground.appspot.com/#?load=3b1d964bfd66dc623c89

    0 讨论(0)
  • 2020-12-22 17:17

    Here's my go at it in Python. Pretty sure it works but haven't tested it.

    Two passes through the list (but deleting the list as it finds 'water'):

    def answer(heights):

    def accWater(lst,sumwater=0):
        x,takewater = 1,[]
        while x < len(lst):
            a,b = lst[x-1],lst[x]
            if takewater:
                if b < takewater[0]:
                    takewater.append(b)
                    x += 1
                else:
                    sumwater += sum(takewater[0]- z for z in takewater)
                    del lst[:x]
                    x = 1
                    takewater = []
            else:
                if b < a:
                    takewater.extend([a,b])
                    x += 1
                else:
                    x += 1
        return [lst,sumwater]
    
    heights, swater = accWater(heights)
    x, allwater = accWater(heights[::-1],sumwater=swater)
    return allwater
    
    0 讨论(0)
提交回复
热议问题