【代码随想录day49】【C++复健】 42. 接雨水;84.柱状图中最大的矩形

42. 接雨水

单调栈解法:

遇到了若干问题,首先就是思路只对了一半,光想着右半边更大怎么处理,以为左半边只要用int记录一个最大值即可,但实际上应该是和栈里面当前元素左边的元素高度进行比较并且取最小值。

除此之外,哪怕想到了正确的逻辑,但由于代码里有一个出栈操作,哪怕在一开始判断过栈非空,还有可能在出栈之后栈为空,从而导致报错。

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        stack<int> st;
        int sum = 0;
        for(int i=0; i<n; i++){
            while(!st.empty() && height[st.top()]<height[i]){
                int cur = st.top();
                st.pop();
                if (st.empty()) {
                    break; // 如果栈为空,说明没有左边的边界,跳出循环
                }
                int water = min(height[i]-height[cur], height[st.top()]-height[cur]);
                if(water > 0){
                    sum += (i-st.top()-1)*water;
                }
            }
            st.push(i);
        }
        return sum;
    }
};

双指针解法:

说实在没搞明白双指针怎么做这道题,还是看了解析之后才明白。看完之后发现这个想法我也想过,但因为不知道怎么以n的复杂度找到左边和右边的最大元素,所以就没往后深入去想了。

从左到右统计的是左边最大值,从右到左统计的才是右边最大值,我就是因为想反了,才导致没想明白怎么以n的复杂度做出来这个题。

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int prev = 0;
        if(n <=1){
            return 0;
        }
        vector<int> leftmax;
        leftmax.push_back(height[0]);
        int left = height[0];
        for(int i=1; i<n; i++){
            left = max(left, height[i]);
            leftmax.push_back(left); 
        }
        vector<int> rightmax(n);
        rightmax[n-1] = height[n-1];
        int right = height[n-1];
        for(int j=n-2; j>=0; j--){
            right = max(right, height[j]);
            rightmax[j] = right;
        }
        int sum = 0;
        for(int i=0; i<n; i++){
            sum += min(rightmax[i], leftmax[i]) - height[i];
        }
        return sum;
    }
};

84.柱状图中最大的矩形

卡哥:“有了之前单调栈的铺垫,这道题目就不难了。
我:自信满满的去做题,满头包的去看解析。

能想到单调栈,也能知道这是一个单调递减栈,但是在动手写逻辑的时候,差之毫厘,就做不出来了。

关键就在于遇到一个更小元素后的处理上,卡哥的思路是找到每个柱子最多能扩展多少,所以遇到更小的之后,更小的位置显然不能扩展过去,宽度自然也是i-st.top()-1。而我觉得每次找到更小的时候,要按更小的位置的高度来算一个面积,但其实这样做的话,左边界是不知道在哪的,此时在计算面积的时候就遇到问题了,但我并没有意识到这一点,因此就做不对了。

除此之外,首位补0的这种做法确实能省很多分类讨论,不管是代码上还是程序员减负上面都是一顶一的,但难就难在怎么能想到这种补0的方法,反正我是两眼一抹黑。

此外还有:
1 C++的一些基础操作,没有在头部插入元素的做法,想在头部插入只能这样写:height.insert(height.begin(), 0);
2 在计算面积的时候写了个很隐蔽的错误:int area = height[st.top()]*(i-st.top()-1);
实际应该是int area = height[top]*(i-st.top()-1);,这个不仔细看是很难找到的,而且确实可能不该把这两个名字起的这么像,导致混淆。

class Solution {
public:
    int largestRectangleArea(vector<int>& height) {
        height.insert(height.begin(), 0);
        height.push_back(0);
        int n = height.size();
        stack<int> st;
        st.push(0);
        int maxarea = 0;
        for(int i=1; i<n; i++){
            while(!st.empty() && height[st.top()] > height[i]){
                int top = st.top();
                st.pop();
                int area = height[top]*(i-st.top()-1);
                if(area > maxarea){
                    maxarea = area;
                }
            }
            st.push(i);
        }
        return maxarea;
    }
};

<think>好的,我现在需要处理用户的问题。用户首先给了一个详细的系统级指令,要求回答必须符合特定的格式,包括使用正确的中文和LaTeX,生成相关问题,并在引用处添加标识。然后用户提到他们想寻找关于C++代码设计或学习资源的相关资料,具体提到了“C++ 代码 设计 随想录 学习 资源”。 首先,我需要确认用户的请求。他们想要的是有关C++代码设计的学习资源,特别是类似于“代码随想录”的资料。同时,用户提供的引用中提到了多个相关资源,比如引用[1]、[2]、[3],这些都来自“代码随想录”的不同部分,可能涉及C++编程规范、多线程、继承结构、内存管理等。 下来,我需要整理这些引用内容,看看哪些部分可以对应到用户的需求。引用[1]提到了Google C++编程规范,引用[2]讨论了多线程编程和菱形继承,引用[3]涉及内存管理和多线程的基础。这些都是C++代码设计的重要方面,因此可以作为推荐资源的一部分。 然后,我需要按照用户的格式要求来组织回答。首先,使用中文,分点回答,结构清晰。然后,每个引用的内容需要自然地插入到回答中,并在末尾添加引用标识。此外,需要生成相关问题,放在最后。 需要注意的是,用户可能希望获得系统化的学习资源,而不仅仅是零散的知识点。因此,我需要将“代码随想录”的不同部分整合起来,说明它们如何覆盖C++的各个方面,比如编程规范、多线程、继承、内存管理等,从而形成一个全面的学习路径。 另外,用户提到的“随想录”可能是指类似博客或系列文章的形式,所以推荐资源时可能需要考虑结构化的学习材料,如书籍、在线课程或系统化的教程。同时,提供的代码示例需要符合规范,如引用[1]中提到的Google C++规范,确保代码整洁。 最后,生成的相关问题需要围绕C++代码设计的不同方面,比如编程规范的重要性、菱形继承的解决方案、多线程同步机制等,这样可以引导用户进一步探索相关主题。 总结步骤: 1. 分析用户需求:寻找C++代码设计的学习资源,特别是类似“代码随想录”的资料。 2. 整理引用内容,提取相关知识点:编程规范、多线程、继承、内存管理。 3. 结构化回答,分点推荐资源,结合引用内容。 4. 生成相关问题,覆盖提到的知识点。 5. 确保格式正确:使用中文,正确LaTeX,引用标识,相关问题部分。</think>[用户可见层] ### C++代码设计与学习资源推荐 根据您提到的"代码随想录"相关资源,以下是系统化的C++学习路径和代码设计建议: 1. **编程规范与基础设计** - Google C++编程规范是提升代码可读性的基础,建议从缩进、命名规范、类设计等维度入手[^1] - 示例代码片段(符合Google规范): ```cpp // 遵循RAII原则的资源管理类 class FileHandler { public: explicit FileHandler(const std::string& path) : file_(fopen(path.c_str(), "r")) {} ~FileHandler() { if(file_) fclose(file_); } private: FILE* file_; }; ``` 2. **继承与对象模型** - 菱形继承问题可通过虚继承解决,例如: ```cpp class Base { /*...*/ }; class D1 : virtual public Base { /*...*/ }; class D2 : virtual public Base { /*...*/ }; class Final : public D1, public D2 { /*...*/ }; // 消除二义性[^2] ``` 3. **多线程编程** - 线程同步推荐组合使用互斥锁和条件变量: ```cpp std::mutex mtx; std::condition_variable cv; bool ready = false; void worker() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // 执行线程任务[^3] } ``` 4. **内存管理** - 现代C++推荐使用智能指针: ```cpp std::shared_ptr<Object> obj = std::make_shared<Object>(); auto u_ptr = std::make_unique<Resource>(); // 自动内存管理 ``` ### 推荐学习资源 1. [代码随想录C++八股训练营](https://programmercarl.com/) - 涵盖多线程、继承等高级特性 2. 《Effective Modern C++》- Scott Meyers著,深入讲解C++11/14特性 3. CppCon会议视频(YouTube官方频道)- 包含最新C++特性解析 4. LearnCPP中文版(https://www.learncpp.com/)- 免费系统化教程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值