-
42. 接雨水
【思路】- 双指针解法:只是单纯的、直接的、麻烦的、客观的、所有的找到了每个元素左边的最高点和右边的最高点,而当前元素能装的雨水又取决于两边最高点的最低点(最低点 - 当前元素的值),遍历所有元素计算每个元素能装多少雨水,加起来即可;
- 动态规划:双指针解法是在每次遍历到元素的时候又遍历一遍找左边届和右边界,我们可以提前存储每个元素的左边界和右边界,用的时候取就可以~
- 单调栈:
- 当前遍历的元素高度 < 栈顶元素的高度:元素入栈;
- 当前遍历的元素高度 = 栈顶元素的高度:弹出上一个,当前元素入栈;
- 当前遍历的元素高度 > 栈顶元素的高度:取出栈顶元素(mid,装雨水的底部),然后比较现在的栈顶元素高度(left)和当前元素的高度选取最小值再减去 mid 高度就是装雨水的高度,用当前元素的下标减去 left 再减一就是装雨水的宽度,面积为两者乘积。
// 双指针解法 var trap = function(height) { let sum = 0; for (let i = 0; i < height.length; i++) { if (i === 0 || i === height.length - 1) continue; let lHeight = height[i], // 左边界 rHeight = height[i]; for(let l = i - 1; l >= 0; l--) { if (height[l] >lHeight) lHeight = height[l]; } for(let r = i + 1; r < height.length; r++) { if (height[r] > rHeight) rHeight = height[r]; } let h = Math.min(rHeight, lHeight) - height[i]; if (h > 0) sum += h; } return sum; }; // 动态规划:先记录每个元素的左边最大值和右边最大值,然后再遍历算出每个元素可以装的雨水,比双指针每次循环时都要遍历找一遍最大值要好 var trap = function(height) { let sum = 0, rHeight = new Array(height.length).fill(0), lHeight = new Array(height.length).fill(0); // 记录每个元素的左边的最大高度 lHeight[0] = height[0]; for(let i = 1; i < height.length; i++) { lHeight[i] = Math.max(height[i], lHeight[i - 1]); } // 记录每个元素右边的最大高度 rHeight[height.length - 1] = height[height.length - 1]; for (let i = height.length - 2; i >= 0; i--) { rHeight[i] = Math.max(height[i], rHeight[i + 1]); } for(let i = 0; i < height.length; i++) { let h = Math.min(rHeight[i], lHeight[i]) - height[i]; if (h > 0) sum += h; } return sum; } // 单调栈 var trap = function(height) { if (height.length <= 2) return 0; let stack = [], area = 0; stack[0] = 0; // 初始化为第一个元素下标 for (let i = 0; i < height.length; i++) { if (height[i] < height[stack[stack.length - 1]]) { stack.push(i); }else if(height[i] === height[stack[stack.length - 1]]) { stack.pop(); stack.push(i); } else { while(stack.length && height[i] > height[stack[stack.length - 1]]) { let mid = stack.pop(); if (stack.length !== 0) { const left = stack[stack.length - 1]; const h = Math.min(height[i], height[left]) - height[mid]; const w = i - left - 1; if (h * w > 0) area += h * w; } } stack.push(i); } } return area; }
-
503. 下一个更大元素II
【思路】这道题比之前的题多了一个环形的条件,我们只要想办法遍历两次即可,可以把 nums 数组拼成由两个 nums 组成的新数组,但这样破坏了 nums 的结构,不太好,我们可以用取余的方法来做i % nums.length
,这样就相当于遍历了两遍~var nextGreaterElements = function(nums) { let res = new Array(nums.length).fill(-1), stack = []; for (let i = 0; i < nums.length * 2; i++) { // 取余可以使数组循环两遍 while(stack.length && nums[i % nums.length] > nums[stack[stack.length - 1]]) { const top = stack.pop(); res[top] = nums[i % nums.length]; } stack.push(i % nums.length); } return res; };
https://www.programmercarl.com/