力扣网C语言编程题:接雨水(双指针法)

一. 简介

前面文章是以动态规划方法实现的,文章如下:

力扣网C语言编程题:接雨水(动态规划实现)-CSDN博客

本文继续针对力扣网的接雨水问题,以另一种解题思路(双指针) 以 C语言实现和Python实现。

二. 力扣网C语言编程题:接雨水(双指针法)

题目:接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 2:
输入:height = [4,2,0,3,2,5]
输出:9

提示:
    n == height.length
    1 <= n <= 2 * 104
    0 <= height[i] <= 105

初步思路:

暴力解法是最直观的方法,它直接按照问题的定义来计算每个位置能够接多少水。

从左到右遍历数组元素,计算每个柱子的接水量,然后,不断累加即可。但是问题的关键是如何计算每个柱子能接的雨水量?

通过柱型图观察可知,只有低洼的位置才会接到雨水。具体意思就是,某个元素 nums[i]的左侧与右侧所有元素只要高于其本身就可接到雨水。
核心原理:

雨水能被接住的条件是:左右两侧存在比当前位置更高的墙。

每个位置能接的雨水量 = min (左侧最高墙高度,右侧最高墙高度) - 当前墙高度(若结果为负则取 0,其中左侧指的是某个元素的左侧所有元素值最大的元素)。

解题思路二:(双指针)

从动态规划方法可知,当 left_max_arr[i] > right_max_arr[i]时,接水的高度由 right_max_arr[i]决定。同理,当 right_max_arr[i] > left_max_arr[i]时,接水的高度由 left_max_arr[i]决定。

所以,可以认为如果一端有更高的柱形元素值,接水的高度依赖于当前方向的高度(即从做到右),当我们发现右侧的柱形高度低于左边时,我们则可以开始从右侧方向遍历元素(即从右向左);

具体方法:

1. 定义两个指针(类似指针的作用,而非指针类型),left和 right;

2. 对数组进行遍历,同时从数组的首部和尾部开始:比较 height[left] 和 heigth[right] 大小。

如果 height[left]  < height[right],则开始从左向右开始计算接水量,再判断 此时元素是否大于 left_max值,height[left] > left_max则接不到雨水(更新left_max值),否则接水量累加;

如果 height[left]  > height[right],则开始从右向左开始计算接水量,再判断 此时元素是否大于 right_max值,height[right] > right_max则接不到雨水(更新right_max值),否则接水量累加;

3. 最后,返回接水量;

C语言实现如下:

#include 

int trap(int *height, int heightSize) {
    if((height == NULL) || (heightSize < 2)) {
        return 0;
    }

    int receive_water = 0;
    int left = 0;
    int right = heightSize-1;
    int left_max = height[0], right_max = height[heightSize-1];

    while(left < right) {
        //左边 < 右边,则从左向右进行计算
        if(height[left] < height[right]) {
            //本元素高于左边前面最大元素,则不会接到雨水
            if(height[left] > left_max) { 
                left_max = height[left];
            }
            else{
                receive_water += (left_max-height[left]);
            }
            left++;
        }   
        else {//左边 > 右边,则从右向左进行计算
            //本元素高于左边前面最大元素,则不会接到雨水
            if(height[right] > right_max) {
                right_max = height[right];
            }
            else {
                receive_water += (right_max-height[right]);
            }
            right--;
        } 
    }

    return receive_water;
}

可以看出,这种方法的时间复杂度为O(n),空间复杂度为 O(1)。

上面代码中,left_max和 right_max这两个变量的边界值也同时赋0,经过在力扣网上测试也是可以编译通过的。

python实现如下:

class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        left = 0
        right = (n-1)
        receive_rainwater = 0
        left_max = height[0]
        right_max = height[n-1]

        while(left < right):
            if(height[left] < height[right]): //如果左边 < 右边,则从左向右计算
                if(height[left] > left_max):
                    left_max = height[left]
                else:
                    receive_rainwater += left_max-height[left]
                left += 1
            else:                         //如果左边 > 右边,则从右向左计算
                if(height[right] > right_max): 
                    right_max = height[right]
                else:
                    receive_rainwater += right_max-height[right]
                right -= 1

        return receive_rainwater

可以看出,思路是一样的。python实现上跟 C 有些类似的。

你可能感兴趣的:(逻辑编程题,C语言,c语言,leetcode,算法)