본문 바로가기
알고리즘 문제풀이/leetcode

[leetcode 42] Trapping Rain Water

by m2162003 2020. 11. 10.

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

 

Example 1:

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1] Output: 6 Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.

Example 2:

Input: height = [4,2,0,3,2,5] Output: 9

 

Constraints:

  • n == height.length
  • 0 <= n <= 3 * 104
  • 0 <= height[i] <= 105

문제 풀이:

nhn 1차 pretest에서 나왔는데 못푼 문제이다.

 

방법은 3가지: brute force/stack/2 pointer

 

1 brute force 이용

 

maxHeight 배열 만들기

1. 왼쪽부터 오른쪽으로 막대기의 최대 길이를 업데이트 하여 저장한다. max(maxLen, height[i])

2. 다시 오른쪽부터 왼쪽으로 막대기의 최대길이를 업데이트하여 저장하되 이 때는 min(기존에 저장된 최대 길이, 현재 최대 길이)를 저장한다.

 

3. 이제 maxHeight 배열에서 본래 빌딩 높이 배열을 빼준다. 이 때 차이값을 정답에 더해주면 된다.

파란색은 왼쪽에서부터 최대 길이를 체크한 것이고 빨간 색은 오른쪽에서부터 최대 길이를 체크한 것이다.

 

1,2를 마치고 나면 maxHeight에 저장된 값은 0 1 1 2 2 2 2 3 2 2 2 1 이 된다.

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        vector<int> maxArr(n,0);
        int maxHeight = 0;
        for(int i=0; i<n; i++){
            maxHeight = max(maxHeight, height[i]);
            maxArr[i] = maxHeight;
        }
        maxHeight = 0;
        for(int i=n-1; i>-1; i--){
            maxHeight = max(maxHeight, height[i]);
            
            if(maxHeight < maxArr[i]){
             maxArr[i] = maxHeight;   
            }
        }
        
        int ans=0;
        for(int i=0; i<n; i++){
            ans+= maxArr[i] - height[i];
        }
        return ans;
    }
};

 

2 stack 사용

빗물이 고이는 시점은 막대기 길이가 긴거 -> 작은거 순서로 나오다가 갑자기 긴 막대기가 나왔을 때이다. (작은거 -> 긴 거 면 빗물 안고임 empty에서 break하는 이유)

따라서 스택이 비어있거나 이전 막대기가 현재 막대기보다 길다면 계속 push한다.

이전 막대기보다 긴 막대기가 등장했다면 그 때부터 빗물의 양을 측정한다.

 

 

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int idx = 0, ans=0;
        
        stack<int> st;
       
        while(idx<n){
            
                while(!st.empty() && height[st.top()] < height[idx]){
                    int top = st.top();
                    st.pop();
                    
                    if(st.empty()){
                        break;
                    }
                    
                    int width = idx - st.top() -1;
                    int tmp_height = min(height[idx], height[st.top()]) - height[top];
                    
                    ans += width * tmp_height;
                }
                st.push(idx++);

            
        }
        return ans;
    }
};

 

 

3 투포인터 사용

 

leftMax는 left의 왼쪽에, rightMax는 right의 오른쪽에 있을 것이다. 

leftMax< rightMax의 의미는 오른쪽에 현재보다 긴 막대기가 존재할 것이라는 의미이므로 짧은 막대기를 기준으로 물의 양을 계산한다.

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int left = 0, right = n-1, ans=0;
        
        int leftMax = 0, rightMax=0;
        
        while(left<right){
            leftMax = max(leftMax, height[left]);
            rightMax = max(rightMax, height[right]);
            
            if(leftMax < rightMax){
                ans += max(0, leftMax - height[left++]);
            }else {
                ans += max(0, rightMax - height[right--]);
            }
        }
        
        return ans;
    }
};

'알고리즘 문제풀이 > leetcode' 카테고리의 다른 글

[leetcode 54] Spiral Matrix  (0) 2020.11.10
[leetcode 28] Implement strStr()  (0) 2020.11.10
[leetcode 48] Rotate Image  (0) 2020.11.09
[leetcode 412] Fizz Buzz  (0) 2020.11.09
[leetcode 239] Sliding Window Maximum  (0) 2020.11.09

댓글