leecode更新
This commit is contained in:
parent
67b46dbcac
commit
82812f32ff
|
|
@ -0,0 +1,199 @@
|
||||||
|
package com.markilue.leecode.stackAndDeque;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.stackAndDeque
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-09-18 09:14
|
||||||
|
* @Description: TODO 力扣42题 接雨水:
|
||||||
|
* 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class Trap {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
|
||||||
|
System.out.println(trap3(height));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
int[] height = {4, 2, 0, 3, 2, 5};
|
||||||
|
System.out.println(trap2(height));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
int[] height = {5, 4, 1, 2};
|
||||||
|
System.out.println(trap2(height));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test3() {
|
||||||
|
int[] height = {5, 5, 1, 3};
|
||||||
|
System.out.println(trap3(height));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test4() {
|
||||||
|
int[] height = {2, 0, 1, 1, 0, 1, 3, 2, 1, 2, 1};
|
||||||
|
System.out.println(trap3(height));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己的思路:这题和滑动窗口的题非常相似,都是需要记录在右边比他小的值,如果右边的比他大则出栈
|
||||||
|
* 因此仍然使用一个双端队列(单调队列)进行遍历,遇上下一个比他大的就出栈,则接雨水数就等于索引之差
|
||||||
|
* 速度击败30.41%,内存击败71.84%
|
||||||
|
*
|
||||||
|
* @param height
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int trap(int[] height) {
|
||||||
|
|
||||||
|
//int[元素,索引]
|
||||||
|
Deque<int[]> deque = new LinkedList<>();
|
||||||
|
|
||||||
|
//记录上一次出栈的高度
|
||||||
|
int lastHeight = 0;
|
||||||
|
int result = 0;
|
||||||
|
boolean flag = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < height.length; i++) {
|
||||||
|
while (deque.size() != 0 && deque.peek()[0] <= height[i]) {
|
||||||
|
int[] poll = deque.poll();
|
||||||
|
//高度乘以宽度=蓄水量 =>(i-poll[1]-1)索引之差即宽度;这次出栈的高度-lastHeight即高度
|
||||||
|
result += (i - poll[1] - 1) * (poll[0] - lastHeight);
|
||||||
|
lastHeight = poll[0];
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
//防止在内部时,不出站计算不了对应的雨水量的情况
|
||||||
|
//这里使用flag记录是否进入过上面的接雨水环节,如果接过雨水还没出栈完,那么计算那部分的雨水量
|
||||||
|
//这里使用if即可,因为flag出来以后一定遇上的是比他大的第一个数
|
||||||
|
if (deque.size() != 0 && flag && height[i] > lastHeight) {
|
||||||
|
int[] peek = deque.peek();
|
||||||
|
//高度乘以宽度=蓄水量 =>(i-poll[1]-1)索引之差即宽度;这次这次高度-lastHeight即高度
|
||||||
|
result += (i - peek[1] - 1) * (height[i] - lastHeight);
|
||||||
|
}
|
||||||
|
flag = false;
|
||||||
|
deque.push(new int[]{height[i], i});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方动态规划解法:只要记录左边柱子的最高高度和右边柱子的最高高度,就可以计算当前位子的雨水面积
|
||||||
|
* TODO 当前位置的雨水面积: [min(左边柱子的最高高度,右边柱子的最高高度)-当前柱子高度]*单位宽度
|
||||||
|
* 因此可以分别将左右两边柱子的最高高度分别记录在两个数组maxLeft和maxRight中,这时就用到了动态规划
|
||||||
|
* 精髓在于当前位置的雨水面积的计算方式
|
||||||
|
* 时间复杂度O(n),空间复杂度O(n)
|
||||||
|
* 速度超过76.2%,内存超过79.9%
|
||||||
|
*
|
||||||
|
* @param height
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int trap2(int[] height) {
|
||||||
|
|
||||||
|
int n = height.length;
|
||||||
|
int[] maxLeft = new int[n];
|
||||||
|
|
||||||
|
maxLeft[0] = height[0];
|
||||||
|
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
maxLeft[i] = Math.max(height[i], maxLeft[i - 1]);
|
||||||
|
}
|
||||||
|
int[] maxRight = new int[n];
|
||||||
|
|
||||||
|
maxRight[n - 1] = height[n - 1];
|
||||||
|
|
||||||
|
for (int i = n - 2; i >= 0; i--) {
|
||||||
|
maxRight[i] = Math.max(height[i], maxRight[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
result += Math.min(maxLeft[i], maxRight[i]) - height[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方单调栈解法:使用一个单调栈维护一个单调递减的栈,栈顶元素小于栈低元素,栈中存放索引
|
||||||
|
* 栈中必须要有两个元素才会有凹槽,才能接雨水
|
||||||
|
* 速度击败39.81%,内存击败86.4%
|
||||||
|
* @param height
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int trap3(int[] height) {
|
||||||
|
|
||||||
|
int n = height.length;
|
||||||
|
|
||||||
|
Deque<Integer> deque = new LinkedList<>();
|
||||||
|
|
||||||
|
int result=0;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
while (!deque.isEmpty() && height[i] > height[deque.peek()]) {
|
||||||
|
int top=deque.pop();
|
||||||
|
if(deque.isEmpty()){
|
||||||
|
//栈中必须有两个元素才会有凹槽
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int left=deque.peek();
|
||||||
|
int currWidth = i - left - 1;
|
||||||
|
int currHeight = Math.min(height[left], height[i]) - height[top];
|
||||||
|
result += currWidth * currHeight;
|
||||||
|
}
|
||||||
|
deque.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方进阶双指针法:思路是动态规划法为基础,同时将空间复杂度降到了O(1)
|
||||||
|
* 注意到下标 i 处能接的雨水量由 leftMax[i] 和 rightMax[i] 中的最小值决定。
|
||||||
|
* 由于数组 leftMax 是从左往右计算,数组 rightMax 是从右往左计算,因此可以使用双指针和两个变量代替两个数组。
|
||||||
|
*
|
||||||
|
* TODO 精髓在于:如果左边比右边的小,那么就算左边的高度,因为右边比左边大了,那么左边的水一定可以蓄起来;反之亦然
|
||||||
|
* 速度超过100%,内存超过18.38%
|
||||||
|
*/
|
||||||
|
public int trap4(int[] height) {
|
||||||
|
|
||||||
|
int ans = 0;
|
||||||
|
int left = 0, right = height.length - 1;
|
||||||
|
int leftMax = 0, rightMax = 0;
|
||||||
|
while (left < right) {
|
||||||
|
leftMax = Math.max(leftMax, height[left]);
|
||||||
|
rightMax = Math.max(rightMax, height[right]);
|
||||||
|
if (height[left] < height[right]) {
|
||||||
|
//如果左边的小,那么左边的水一定可以蓄起来,那么就计算左边的水
|
||||||
|
ans += leftMax - height[left];
|
||||||
|
++left;
|
||||||
|
} else {
|
||||||
|
ans += rightMax - height[right];
|
||||||
|
--right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue