42接雨水

一、前言

标签:动态规划、栈运用、双指针。

问题来源LeetCode 5 难度:困难。

问题链接:https://leetcode-cn.com/problems/longest-palindromic-substring/

 

二、题目

 

三、思路

三种解题方法。

方法一:动态规划

  1. 找到数组中从下标 i 到最左端最高的条形块高度 left_max。
  2. 找到数组中从下标 i 到最右端最高的条形块高度 right_max。
  3. 扫描数组 height 并更新答案:
  4. 累加 min(max_left[i],max_right[i])−height[i] 到 ansans 上

复杂度分析:时间复杂度O(n), 空间复杂度O(n)

方法二:栈的应用

使用栈来存储条形块的索引下标。

遍历数组:

当栈非空且 height[current] > height[st.top()]。意味着栈中元素可以被弹出。弹出栈顶元素 top。计算当前元素和栈顶元素的距离,准备进行填充操作。distance = current−st.top() − 1,找出界定高度,bounded_height = min(height[current], height[st.top()]) − height[top],往答案中累加积水量ans += distance×bounded_height

将当前索引下标入栈。

将 current 移动到下个位置。

时间复杂度:O(n), 空间复杂度:O(n)

方法三:双指针

和栈用有些类似,两头分别一个指针,向中间遍历。

 

四、编码实现

//==========================================================================
/*
* @file    : 042_Trap.h
* @label   : 动态规划、栈运用、双指针
* @blogs   : https://blog.csdn.net/nie2314550441/article/details/107498351
* @author  : niebingyu
* @date    : 2020/07/20
* @title   : 42.接雨水
* @purpose : 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
*
* 示例1:
* 输入: [0,1,0,2,1,0,1,3,2,1,2,1]
* 输出: 6
*
* 来源:力扣(LeetCode)
* 难度:困难
* 链接:https://leetcode-cn.com/problems/trapping-rain-water/
*/
//==========================================================================
#pragma once
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <assert.h>
using namespace std;

#define NAMESPACE_TRAP namespace NAME_TRAP {
#define NAMESPACE_TRAPEND }
NAMESPACE_TRAP

/*
* 算法
* 找到数组中从下标 i 到最左端最高的条形块高度 left_max。
* 找到数组中从下标 i 到最右端最高的条形块高度 right_max。
* 扫描数组 height 并更新答案:
* 累加 min(max_left[i],max_right[i])−height[i] 到 ansans 上
*/
// 方法一,动态规划
// 时间复杂度:O(n), 空间复杂度:O(n)
class Solution_1 
{
public:
    int trap(vector<int>& height)
    {
        if (height.empty())
            return 0;

        int ans = 0;
        int size = height.size();
        vector<int> left_max(size), right_max(size);
        left_max[0] = height[0];
        for (int i = 1; i < size; i++) 
            left_max[i] = max(height[i], left_max[i - 1]);

        right_max[size - 1] = height[size - 1];
        for (int i = size - 2; i >= 0; i--) 
            right_max[i] = max(height[i], right_max[i + 1]);

        for (int i = 1; i < size - 1; i++) 
            ans += min(left_max[i], right_max[i]) - height[i];

        return ans;
    }
};

/*
* 算法
* 使用栈来存储条形块的索引下标。
* 遍历数组:
* 	当栈非空且 height[current] > height[st.top()]
* 		意味着栈中元素可以被弹出。弹出栈顶元素 top。
* 		计算当前元素和栈顶元素的距离,准备进行填充操作
* 		distance = current−st.top()−1
* 		找出界定高度
* 		bounded_height = min(height[current], height[st.top()])−height[top]
* 		往答案中累加积水量ans += distance×bounded_height
* 将当前索引下标入栈
* 将 current 移动到下个位置
*/
// 方法二,栈的应用
// 时间复杂度:O(n), 空间复杂度:O(n)
class Solution_2
{
public:
    int trap(vector<int>& height)
    {
        int ans = 0, current = 0;
        stack<int> st;
        while (current < height.size()) 
        {
            while (!st.empty() && height[current] > height[st.top()]) 
            {
                int top = st.top();
                st.pop();
                if (st.empty())
                    break;
                int distance = current - st.top() - 1;
                int bounded_height = min(height[current], height[st.top()]) - height[top];
                ans += distance * bounded_height;
            }
            st.push(current++);
        }

        return ans;
    }
};

// 方法三,使用双指针
// 时间复杂度:O(n), 空间复杂度:O(1)
class Solution_3
{
public:
    int trap(vector<int>& height)
    {
        int left = 0, right = height.size() - 1;
        int ans = 0;
        int left_max = 0, right_max = 0;
        while (left < right) 
        {
            if (height[left] < height[right]) 
            {
                height[left] >= left_max ? (left_max = height[left]) : ans += (left_max - height[left]);
                ++left;
            }
            else 
            {
                height[right] >= right_max ? (right_max = height[right]) : ans += (right_max - height[right]);
                --right;
            }
        }
        return ans;
    }
};

以下为测试代码//
// 测试 用例 START

void test(const char* testName, vector<int>& height, int expect)
{
    Solution_2 s;
    int result = s.trap(height);

    if (result == expect)
        cout << testName << ", solution passed." << endl;
    else
        cout << testName << ", solution failed. " << endl;
}

// 测试用例
void Test1()
{
    vector<int> height = { 5,0,1,2 };
    int expect = 1;
    test("Test1()", height, expect);
}

void Test2()
{
    vector<int> height = { 0,1,0,2,1,0,1,3,2,1,2,1 };
    int expect = 6;
    test("Test2()", height, expect);
}

NAMESPACE_TRAPEND
// 测试 用例 END
//
void Trap_Test()
{
    cout << "------ start 42.接雨水 ------" << endl;
    NAME_TRAP::Test1();
    NAME_TRAP::Test2();
    cout << "------ end 42.接雨水 --------" << endl;
}

执行结果:

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值