LeetCode:Container With Most Water,Trapping Rain Water

Container With Most Waterhtml

題目連接算法

Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.數組

Note: You may not slant the container.app


算法1:枚舉容器的兩個邊界,時間複雜度O(n^2)。大數據超時大數據

class Solution {
public:
    int maxArea(vector<int> &height) {
        int res = 0, n = height.size();
        for(int i = 0; i < n; i++)//左邊界
            for(int j = i+1; j < n; j++)//右邊界
            {
                int tmp = (j-i)*min(height[i],height[j]);
                if(res < tmp)res = tmp;
            }
        return res;
    }
};

 

對上面的稍加改進,根據當前的已經計算出來的結果以及左邊界的值,能夠算出容器右邊界的下界。不過仍是超時this

class Solution {
public:
    int maxArea(vector<int> &height) {
        int res = 0, n = height.size();
        for(int i = 0; i < n; i++)//左邊界
        {
            if(height[i] == 0)continue;
            for(int j = max(i+1, res/height[i]+i); j < n; j++)//右邊界
            {
                int tmp = (j-i)*min(height[i],height[j]);
                if(res < tmp)res = tmp;
            }
        }
        return res;
    }
};

 

算法2:時間複雜度O(nlogn)。指針

構建結構體包含height和height在原數組中的位置code

struct Node
    {
        int height;
        int index;orm

};htm

對該結構體數組按照height的值遞增排序,假設排序後的數組爲vec.

 

假設f[i] 表示數組vec[i,i+1,…]內全部height按照原來的位置順序排列好之後的最大水量

那麼f[i-1]能夠在O(1)時間內計算出來:由於vec[i-1].height 小於vec[i,i+1,…]內的全部height,因此以vec[i-1].index爲邊界的容器高度爲vec[i-1].height,最大水量只須要分別計算vec[i,i+1,…]內按原始位置排列最前面和最後面的height,取二者的較大值。即下圖中,黑色是最低的,要計算以黑色爲邊界的容器的最大水量,只須要分別和第一個和最後一個計算,去二者較大值

image

class Solution {
    struct Node
    {
        int height;
        int index;
        Node(int h, int i):height(h),index(i){}
        Node(){}
        bool operator < (const Node &a)const
        {
            return height < a.height;
        }
    };
public:
    int maxArea(vector<int> &height) {
        int res = 0, n = height.size();
        if(n <= 1)return 0;
        vector<Node>vec(n);
        for(int i = 0; i < n; i++)
        {
            vec[i].index = i;
            vec[i].height = height[i];
        }
        sort(vec.begin(), vec.end());
        
        int start = vec[n-1].index, end = start;//記錄已經處理完的height的原始位置的左右端點
        for(int i = n-2; i >= 0 ; i--)
        {
            start = min(start, vec[i].index);
            end = max(end, vec[i].index);
            res = max(res, max(vec[i].height*(vec[i].index - start), vec[i].height*(end - vec[i].index)));
        }
        return res;
    }
};

 

 

算法3:時間複雜度O(n),兩個指針i, j分別從先後向中間移動,兩個指針分別表示容器的左右邊界。每次迭代用當前的容量更新最大容量,而後把高度小的邊界對應的指針往中間移動一位。                                         本文地址

正確性證實:因爲水的容量是有較小的那個邊界決定的,所以某次迭代中,假設height[i] < height[j],那麼j 減少確定不會使水的容量增大,只有i 增長才有可能使水的容量增大。可是會不會有這種可能:當前的i 和 某個k (k > j)是最大容量, 這也是不可能的,由於按照咱們的移動規則,既然右指針從k 移動到了j,說明i 的左邊必定存在一個邊界 m,使m > k,那麼[m, k]的容量確定大於[i, k],因此[i,k]不多是最大容量。能夠參考here

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


Trapping Rain Water

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

For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

The above elevation map 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.

注意和上一題的區別,上一題至關於在每一個位置放一個擋板,擋板之間能夠蓄水;這一題是放置寬度爲1的柱子,柱子上面能夠蓄水。

 

算法4:分析某個柱子,發現該柱子上水的高度和其左右兩邊的最高柱子有關,設該柱子左邊全部柱子中最高的爲leftmax,右邊全部柱子中最高的爲rightmax,若是min(leftmax, rightmax) 大於該柱子的高度,那麼該柱子上能夠蓄水爲min(leftmax, rightmax) - 該柱子高度,若是min(leftmax, rightmax) <= 該柱子高度,則該柱子上沒有蓄水。

能夠從後往前掃描一遍數組求得某個柱子右邊的最高柱子,從前日後掃描一遍數組求得某個柱子左邊的最高柱子, 而後按照上面的分析能夠求得全部的蓄水量。

class Solution {
public:
    int trap(int A[], int n) {
        int res = 0;
        vector<int>rightMax(n);//柱子右邊最大的柱子高度
        int maxv = 0;
        for(int i = n-1; i >= 0; i--)
        {
            rightMax[i] = maxv;
            maxv < A[i] ? maxv = A[i] : maxv;
        }
        maxv = 0;
        int conHeight;
        for(int i = 0; i < n; i++)
        {//此時maxv爲柱子i左邊最大的柱子高度
            conHeight = min(maxv, rightMax[i]);
            if(conHeight > A[i])
                res += conHeight - A[i];
            maxv < A[i] ? maxv = A[i] : maxv;
        }
        return res;
    }
};

上面的代碼時間空間複雜度都是O(n),掃描了兩次數組

 

算法5:能夠換一種思路,以下圖,若是咱們求出了兩個紅色框的面積,而後再減去框內黑色柱子的面積,就是水的面積了,時間複雜度O(N),空間O(1), 數組掃描2次

image

如何求紅色框內的面積呢,咱們先求出最大的柱子高度,而後左右分開求。求面積是是一層一層的累加

image

class Solution {
public:
    int trap(int A[], int n) {
        int maxHeight = 0, maxIdx = 0;
        for(int i = 0; i < n; i++)//求最大高度
            if(A[i] > maxHeight)
            {
                maxHeight = A[i];
                maxIdx = i;
            }
        int height = 0;
        int pillarArea = 0;//柱子面積
        int totalArea = 0;//總面積
        for(int i = 0; i < maxIdx; i++)
        {
            if(A[i] > height)
            {
                totalArea += (A[i] - height)*(maxIdx - i);
                height = A[i];
            }
            pillarArea += A[i];
        }
        height = 0;
        for(int i = n-1; i > maxIdx; i--)
        {
            if(A[i] > height)
            {
                totalArea += (A[i] - height)*(i - maxIdx);
                height = A[i];
            }
            pillarArea += A[i];
        }
        return totalArea - pillarArea;
    }
};

 

算法6:參考here,也是和算法5同樣求面積,可是這裏利用上一題的左右指針思想,只須要掃描一遍數組

class Solution {
public:
    int trap(int A[], int n) {
        int left = 0, right = n-1;
        int totalArea = 0, pillarArea = 0, height = 0;
        while(left <= right)
        {
            if(A[left] < A[right])
            {
                if(A[left] > height)
                {
                    totalArea += (A[left]-height)*(right - left + 1);
                    height = A[left];
                }
                pillarArea += A[left];
                left++;
            }
            else
            {
                if(A[right] > height)
                {
                    totalArea += (A[right]-height)*(right - left + 1);
                    height = A[right];
                }
                pillarArea += A[right];
                right--;
            }
        }
        return totalArea - pillarArea;
    }
};

 

 

【版權聲明】轉載請註明出處http://www.cnblogs.com/TenosDoIt/p/3812880.html

相關文章
相關標籤/搜索