7.20 牛客左程云第2题(个人学习笔记)

来源:互联网 发布:手机淘宝卖家发货流程 编辑:程序博客网 时间:2024/06/15 08:32

题目:给定一个非负数的数组,代表一个容器。例如数组[0,1,0,2,1,0,1,3,2,1,2,1],就是以下图形中黑色的部分。如果用这个容器接水的话,请问可以接多少水?还以这个数组为例,可以接 6 格水,就是以下图形中蓝色的部分。

 要求:实现时间复杂度 O(N),额外空间复杂度 O(1)的解法

解法一:常规解法

对每一个数值求左右侧最大值,然后求出对应水量,水量应为左右侧最小值减去该数值(得出的水量与0比较,取大者);一直遍历到最后一个元素,显然时间复杂度过大。

C++代码

#include<iostream>using namespace std;int max(int a,int b){return a > b ? a : b;}int min(int a, int b){return a < b ? a : b;}int getWater1(int* arr,int length) {if (arr == NULL || length < 3) return 0;int value = 0;for (int i = 1; i <length - 1; i++) {int leftMax = 0;int rightMax = 0;for (int l = 0; l < i; l++) {leftMax = max(arr[l],leftMax);}for (int r = i + 1; r <length; r++) {rightMax = max(arr[r],rightMax);}value += max(0, min(leftMax, rightMax) - arr[i]);}return value;}
解法二:

采用2个辅助数组,用来存放i位置(Left)左侧最高值和(right)右侧最高值.

具体过程是,首先遍历得Left数组,然后反向遍历得Right数组;最后遍历各个位置求水量,知时间复杂度为O(n)但空间复杂度过大

C++代码

int getWater2(int*arr,int length) {if (arr == NULL || length < 3) {return 0;}int n = length - 1;int* leftMaxs = new int[n];leftMaxs[0] =0;for (int i = 1; i < n; i++) //遍历得left数组,表示该位置左侧的最大值{leftMaxs[i] = max(leftMaxs[i - 1], arr[i-1]);}int*rightMaxs = new int[n];rightMaxs[n - 1] = arr[n];for (int i = n - 2; i >= 0; i--) <span style="font-family: Arial, Helvetica, sans-serif;">//遍历得right数组,表示该位置右侧的最大值</span>{rightMaxs[i] = max(rightMaxs[i+1], arr[i + 1]);}int value = 0;for (int i = 1; i <= n-1; i++){ value += max(0,min(leftMaxs[i], rightMaxs[i]) - arr[i]);//取2侧最小值与该位置值相减得水量(还要与0作比较)}return value;}
解法三:

left数组可在解法二的第3个遍历中用一个变量取代,进一步缩小空间复杂度

C++代码如下

int getWater3(int* arr,int length) {if (arr == NULL ||length < 3) {return 0;}int n = length - 1;int*rightMaxs = new int[n];rightMaxs[n - 1] = arr[n];for (int i = n - 2; i >= 0; i--){rightMaxs[i] = max(rightMaxs[i + 1], arr[i + 1]);}int leftMax = arr[0];int value = 0;for (int i = 1; i <= n-1; i++) {value += max(0, min(leftMax, rightMaxs[i]) - arr[i]);leftMax=max(leftMax, arr[i]);//此处相当于解法2的left数组}return value;}

解法四:

不用辅助数组,仅用2个变量代替left与right,符合要求

例子      

      5       4       6       8       2      3      7
      |                                                   |

      L                                                  R

(1)对于4和3  此时左侧最大值为5,  右侧最大值为7;由于4左侧最大值小于右侧,故此时4的水量可算出(想象水桶,水的多少取决于最短的木板) ,即5-4=1;

然后L++ 

 5       4       6       8       2      3      7
          |                                          |

          L                                        R

(2)对于6,3; 左max为5,右max为7,所以6的水量同样可算出,即  5-6=-1,无水量  0,L++

5       4       6       8       2      3      7
                  |                                 |

                  L                                R

(3)对于8和3;左max为6,右max为7,所以8的水量同样可算出,即  6-8=-2,无水量  0,L++

5       4       6       8       2      3      7
                           |                        |

                           L                       R

(4)对于2和3;左max为8,右max为7,此时3的水量可算出,即  7-3=4 ,R--

5       4       6       8       2      3      7
                           |                |

                           L               R

  最后一步  对于2     为7-2=5 

        C++代码

int getWater4(int* arr,int length) {if (arr == NULL || length < 3) {return 0;}int value = 0;int leftMax = arr[0];int rightMax = arr[length - 1];int l = 1;int r = length - 2;while (l <= r) {if (leftMax <= rightMax) {value += max(0, leftMax - arr[l]);leftMax =max(leftMax, arr[l++]);}else {value += max(0, rightMax - arr[r]);rightMax = max(rightMax, arr[r--]);}}return value;}








0 0