zoukankan      html  css  js  c++  java
  • LeetCode 42. Trapping Rain Water 【两种解法】(python排序遍历,C++ STL map存索引,时间复杂度O(nlogn))

    LeetCode 42. Trapping Rain Water

    Python解法

    解题思路:

    本思路需找到最高点左右遍历,时间复杂度O(nlogn),以下为向左遍历的过程。

    1. 将每一个点的高度和索引存成一个元组 (val, idx)
    2. 找到最高的点(可能有多个,任取一个),记为 (now_val, now_idx)。
    3. 向左找第一个val不大于now_val的点(left_val, left_idx)。
    4. 以left_val作为水平面,用height[left_val+1, now_val-1]中每一个点更新ans。
    5. now_val, now_idx = left_val, left_idx。
    6. 如果now_idx >= 0 ,重复执行3;否则执行7。
    7. 同理从最高点向右遍历更新ans。

    向左找的具体操作

    1. 将每一个点的高度和索引存成一个元组 (val, idx)
    2. 将元组按val从大到小排序,若val相等,按idx从大到小排序。实现过程:直接sort,然后reverse。
    3. 从左向右遍历,找到第一个idx小于now_idx的节点(left_val, left_idx),用height[left+1, now-1]中的点更新ans。
    4. 更新now节点为left节点。
    5. 如果now_idx >= 0 ,重复执行3;否则结束循环,开始向右找。

    向右找的具体操作

    1. 将每一个点的高度和索引存成一个元组 (val, idx)
    2. 将元组按val从大到小排序,若val相等,按idx从小到大排序。实现过程:用functools中的cmp_to_key重载排序过程。
    3. 从左向右遍历,找到第一个idx大于now_idx的节点(right_val, right_idx),用height[now+1, right-1]中的点更新ans。
    4. 更新now节点为lright节点。
    5. 如果now_idx >= 0 ,重复执行3;否则执行6。
    6. 输出ans。
    注意:向左向右只有排序不同,其他操作类似,

    利用functools中的cmp_to_key重载排序过程代码如下:

    def mcmp(a, b):
        val1,idx1 = a
        val2,idx2 = b
        if val1 == val2:
            return idx2-idx1
        return val1-val2
    
    from functools import cmp_to_key
    l = [] # l中存元组(val, idx)
    l.sort(reverse=True, key=cmp_to_key(Solution.mcmp))
    

    代码如下

    class Solution:
        # 利用functools中的cmp_to_key重载排序:
        def mcmp(a, b):
            val1,idx1 = a
            val2,idx2 = b
            if val1 == val2:
                return idx2-idx1
            return val1-val2
        
        def trap(self, height: List[int]) -> int:
            if len(height) == 0:
                return 0
            from functools import cmp_to_key
            l = []
            # 将(val, idx)存入l = []中
            for i in range(0, len(height)):
                l.append((height[i],i))
            
            ans = 0
            
            # 往左找
            l.sort(reverse=True)
            h, con = l[0]
            for i in range(1, len(l)):
                val, left = l[i]
                if left < con:
                    for j in range(left+1, con):
                        ans += val - height[j]
                    con = left
            
            # 往右找
            h, con = l[0]
            l.sort(reverse=True, key=cmp_to_key(Solution.mcmp))
            for i in range(1, len(l)):
                val, right = l[i]
                if right > con:
                    for j in range(con+1, right):
                        ans += val - height[j]
                    con = right
            return ans
    

    C++解法

    解题思路:

    本思路与Python类似,需找到最高点左右遍历,时间复杂度O(nlogn)以下为向左遍历的过程。差别在于C++是存map,无须手动排序。

    // m中first存高度val,second存索引集合。
    // set<int> s = m[2]表示高度为2的点的位置集合。
    map<int, set<int>> m;
    

    实现代码如下:

    class Solution {
    public:
        int trap(vector<int>& height) {
            if(height.size() == 0) return 0;
            int ans = 0;
            // m中first存高度val,second存索引集合。
            // set<int> s = m[2]表示高度为2的点的位置集合。
            map<int, set<int>> m;
            // itm表示m的一个迭代器
            map<int, set<int>>::iterator itm;
            set<int> s;
            set<int>::iterator its;
            //将(val, idx)存入map
            int sz = height.size();
            for(int i = 0;i < sz; ++i){
                m[height[i]].insert(i);
            }
            
            //向左找
            itm = --m.end();
            s = itm->second;
            int h = itm->first;
            int left = *s.begin();
            //每次找val小,idx小的
            while(left != -1 && left >= 0){
                s = m[h];
                its = s.lower_bound(left);
                if(its == s.begin()){
                    if(itm == m.begin()){
                        left = -1;
                    }else{
                        --itm;
                        h = itm->first;
                    }
                }else{
                    --its;
                    for(int i = *its+1;i < left; ++i){
                        ans += h-height[i];
                    }
                    left = *its;
                    continue;
                }
            }
            
            
            //向右找
            itm = --m.end();
            s = itm->second;
            h = itm->first;
            int right = *s.begin();
            //每次找val小,idx大的
            while(right != -1 && right < sz){
                s = m[h];
                its = s.upper_bound(right);
                if(its == s.end()){
                    if(itm == m.begin()){
                        right = -1;
                    }else{
                        --itm;
                        h = itm->first;
                    }
                }else{
                    for(int i = right+1;i < *its; ++i){
                        ans += h-height[i];
                    }
                    right = *its;
                    continue;
                }
            }
            return ans;
        }
    };
    
  • 相关阅读:
    C#中的委托和事件(续)【来自张子扬】
    C# 中的委托和事件[转自张子扬]
    .NET多线程编程入门
    python——configparser模块
    logger模块
    python——time模块
    os模块
    python——re模块
    selenium环境搭建
    iOS中的三大定时器
  • 原文地址:https://www.cnblogs.com/zhangjiuding/p/10927628.html
Copyright © 2011-2022 走看看