力扣 407 接雨水2

题目可以自己去力扣看。

  1. /**
  2. * @param {number[][]} heightMap
  3. * @return {number}
  4. */
  5. var trapRainWater = function (heightMap) {
  6. if (heightMap.length <= 2 || heightMap[0].length <= 2) {
  7. return 0;
  8. }
  9. const n = heightMap.length
  10. const m = heightMap[0].length
  11. let vis = {}
  12. let queue = new PriorityQueue()
  13. let res = 0
  14. // 把边缘点加入优先队列
  15. for (let i = 0; i < n; i++) {
  16. vis[i + ',' + 0] = true;
  17. queue.add([heightMap[i][0], i, 0])
  18. vis[i + ',' + (m - 1)] = true;
  19. queue.add([heightMap[i][m - 1], i, m - 1])
  20. }
  21. for (let i = 1; i < m - 1; i++) {
  22. vis[0 + ',' + i] = true;
  23. queue.add([heightMap[0][i], 0, i])
  24. vis[(n - 1) + ',' + i] = true;
  25. queue.add([heightMap[n - 1][i], n - 1, i])
  26. }
  27. // 不断更新接水点
  28. while (queue.size()) {
  29. let [height, curN, curM] = queue.delete()
  30. // 访问相邻点
  31. let x = curN
  32. let y = curM + 1
  33. if (y < m) {
  34. updateNode(x, y, height)
  35. }
  36. y = curM - 1
  37. if (y >= 0) {
  38. updateNode(x, y, height)
  39. }
  40. y = curM
  41. x = curN - 1
  42. if (x >= 0) {
  43. updateNode(x, y, height)
  44. }
  45. x = curN + 1
  46. if (x < n) {
  47. updateNode(x, y, height)
  48. }
  49. }
  50. return res;
  51. // 更新节点信息,如果没访问过就把节点推入优先队列
  52. function updateNode(x, y, height) {
  53. if (!vis[x + ',' + y]) {
  54. vis[x + ',' + y] = true
  55. if (heightMap[x][y] < height) {
  56. res += (height - heightMap[x][y])
  57. }
  58. queue.add([Math.max(height, heightMap[x][y]), x, y])
  59. }
  60. }
  61. };
  62. // 优先队列
  63. class PriorityQueue {
  64. constructor() {
  65. this.arr = [];
  66. }
  67. shiftMinUp() { // 自底向上调整
  68. const { arr } = this;
  69. let i = arr.length - 1;
  70. let j = ~~((i + 1) / 2) - 1;
  71. let temp = arr[i];
  72. while (j >= 0) {
  73. if (temp[0] < arr[j][0]) {
  74. arr[i] = arr[j];
  75. } else {
  76. break;
  77. }
  78. i = j;
  79. j = j = ~~((j + 1) / 2) - 1;
  80. }
  81. arr[i] = temp;
  82. }
  83. shiftDownMin() { // 自顶向下调整
  84. const { arr } = this;
  85. if (!arr.length) {
  86. return arr;
  87. }
  88. let i = 0;
  89. let j = 2 * i + 1;
  90. let temp = arr[0];
  91. while (j < arr.length) {
  92. if (j < arr.length - 1 && arr[j][0] > arr[j + 1][0]) {
  93. j++;
  94. }
  95. if (temp[0] > arr[j][0]) {
  96. arr[i] = arr[j];
  97. } else {
  98. break;
  99. }
  100. i = j;
  101. j = j * 2 + 1;
  102. }
  103. arr[i] = temp;
  104. }
  105. add(num) { // 插入元素的时候在数组最后,也就是在叶子节点,需要往上调整位置
  106. const { arr } = this;
  107. arr.push(num);
  108. this.shiftMinUp();
  109. }
  110. delete() { // 删除时把队尾放到队首,此时可以从上到下调整位置
  111. const { arr } = this;
  112. let d = arr[0];
  113. arr[0] = arr[arr.length - 1];
  114. arr.pop()
  115. this.shiftDownMin();
  116. return d;
  117. }
  118. size() {
  119. return this.arr.length;
  120. }
  121. get() {
  122. return this.arr[0];
  123. }
  124. }