当青训营遇上码上掘金——攒青豆

58 阅读3分钟

当青训营遇上码上掘金

当青训营遇上码上掘金-攒青豆的四种解法

题目描述

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

题目描述

输入:height = [5,0,2,1,4,0,1,0,3] 
输出:17

解法一:

暴力求解,时间复杂度O(n2)O(n^2),空间复杂度O(1)O(1)

解题思路: 统计除去首位外每个柱子上方所接的水的面积,对于每个柱子而言,其所接水的面积取决于左右两边的最大柱子高度中较小的一个。

算法描述:

  1. 依次遍历数组height[1:len(height)-1]中的每个元素;
  2. 当遍历到下标为i的元素时,执行步骤3、4、5;
  3. 遍历height[:i],找到i对应的最大左元素left_max
  4. 遍历height[i+1:],找到i对应的最大右元素right_max
  5. 下标为i的柱子所接的水为max(min(left_max, right_max)-height[i], 0)
  6. 将全部结果求和得到最终输出;

解法二:

使用动态规划的思想优化解法一的时间复杂度,时间复杂度O(n)O(n),空间复杂度O(n)O(n)

解题思路: 通过一次遍历,将每个元素对应的左大元素和右最大元素记录在数组里。

算法描述:

  1. 分别用left_max_ansright_max_ans来记录左大元素和右最大元素;
  2. 遍历数组height[1:],更新left_max_ans[i] = max(left_max_ans[i-1],height[i-1]);
  3. 遍历数组height[:len(height)-1],更新right_max_ans[i] = max(right_max_ans[i+1],height[i+1]);
  4. 遍历数组height[1:len(height)-1],求每个柱子所承接的水的面积arce = max(min(left_max_ans[i], right_max_ans[i])-height[i], 0);
  5. 求和;

解法三:

使用双指针进一步优化空间复杂度,此题最优解,时间复杂度O(n)O(n),空间复杂度O(1)O(1)

解题思路: 分别用一个变量来记录每个元素对应的左最大元素和右最大元素,用两个指针leftright指向height的两端,left_maxright_max分别表示左最大元素和右最大元素,当height[left-1]<height[right+1]的时候,左最大元素不可能比右最大元素大,因此较小的一方在左边,此时向左扫描left++,否则向右扫描right--

算法描述:

  1. 设置初值left, right, left_max, right_max := 1, len(height)-1, 0, 0
  2. 如果左右指针没重合left<=right,向下执行,否则步骤6;
  3. 如果height[left-1]<height[right+1],执行步骤4,否则执行步骤5;
  4. 更新left_max = max(left_max,height[left-1])计算left对应柱子的面积max(left_max-height[left], 0),移动左指针left++,转至步骤2;
  5. 更新right_max = max(right_max,height[right+1])计算right对应柱子的面积max(right_max-height[right], 0),移动右指针right--,转至步骤2;
  6. 求和;

解法四:

使用单调栈,时间复杂度O(n)O(n),空间复杂度O(n)O(n)

解题思路: 用一个单调递减栈(栈内存储数组下标,下标对应的柱子高度单调递减)来记录i对应柱子左边柱子高度的排列情况,当i比栈顶元素对应的柱子高度低时直接入栈,否则出栈,计算出栈后栈顶元素对应的柱子到i承接的水的面积;

算法描述:

  1. 初始化栈stack
  2. 遍历height[0:]
  3. 如果栈非空或栈顶元素对应的柱子高度小于height[i],执行步骤4,否则执行步骤5;
  4. 出栈,记录栈顶元素对应柱子的高度enum,计算出栈后的栈顶元素对应的柱子到i对应柱子之间所接的水的面积arce := (i-height[stack.top]-1)*;(min(height[stack.top], height[i])-enum),转至步骤3;
  5. i入栈;

PS: 虽然嵌套了两层循环,单每个元素至多访问两遍(出栈、入栈),因此总的时间复杂度为O(n).

附代码

[jcode](https://code.juejin.cn/pen/7198485637895290917)