文章目录
注:p为leetcode顺序题号,o为leetcode上剑指offer第二版题号
p42 接雨水
/**
* 42. 接雨水
* 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
* https://leetcode-cn.com/problems/trapping-rain-water/
*/
/**
* @param {number[]} height
* @return {number}
*/
var trap = function(height) {
let n = height.length, res = 0
if (n === 0) return 0
// leftMax[i]:保存i左边的最大值 rightMax[i]:保存i右边的最大值
let leftMax = [], rightMax = []
// 处理两边界
leftMax[0] = height[0]
rightMax[n - 1] = height[n - 1]
// 从左往右遍历,找i左边的最大值
for (let i = 1; i < n; i ++) {
leftMax[i] = Math.max(leftMax[i - 1], height[i])
}
// 从右往左遍历,找i右边的最大值
for (let i = n - 2; i >= 0; i --) {
rightMax[i] = Math.max(rightMax[i + 1], height[i])
}
// 遍历求每个矩形上方的雨水量:min(左最大值,右最大值)减去当前高度值
for (let i = 0; i < n; i ++) {
res += Math.min(leftMax[i], rightMax[i]) - height[i]
}
return res
};
p54 螺旋矩阵
/**
* 54. 螺旋矩阵
* 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
* https://leetcode-cn.com/problems/spiral-matrix/
*/
/**
* @param {number[][]} matrix
* @return {number[]}
*/
var spiralOrder = function (matrix) {
const res = [], n = matrix.length, m = matrix[0].length,
// dx dy:定义4个方向 st:标记是否遍历过
dx = [0, 1, 0, -1], dy = [1, 0, -1, 0],
st = Array.from({length: n}, () => Array.from({length: m}, () => false))
if (n < 0) return res
// 从左上角开始遍历,x y:位置 d:方向
for (let i = 0, x = 0, y = 0, d = 0; i < n * m; i++) {
res.push(matrix[x][y]) // 遍历
st[x][y] = true // 标记
let a = x + dx[d], b = y + dy[d] //新的方向
// 判断条件:1.走到边界 2.已经遍历过
if (a < 0 || a >= n || b < 0 || b >= m || st[a][b]) {
d = (d + 1) % 4 // 方向变化
a = x + dx[d]
b = y + dy[d]
}
x = a
y = b
}
return res
};
o3 数组中重复的数字
/**
* 剑指 Offer 03. 数组中重复的数字
* 找出数组中重复的数字。
* 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。
* 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
* 请找出数组中任意一个重复的数字。
* https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
*/
/**
* @param {number[]} nums
* @return {number}
*/
var findRepeatNumber = function(nums) {
let n = nums.length
// 遍历一遍,如果不在[0, n-1]范围内,返回-1
for (let x of nums) {
if (x < 0 || x >= n) return -1
}
// 遍历找重复数字
for (let i = 0; i < n; i ++) {
// 一共开辟n个位置,每个数存放在对应值的位置
// 如果当前位置的数不在其对应位置,则将当前位置的数与其应在的位置交换
while (nums[nums[i]] !== nums[i]) {
// [nums[i], nums[nums[i]]] = [nums[nums[i]], nums[i]] 不能这样用,会超时,应该把nums[nums[i]]放在前面,防止nums[i]先改变了
[nums[nums[i]], nums[i]] = [nums[i], nums[nums[i]]]
/* 或者可以先用一个临时变量把nums[i]存储起来
let temp = nums[i];
[nums[i], nums[temp]] = [nums[temp], nums[i]];
*/
}
// 交换完成后,如果当前位置的数还不在对应位置,说明有重复值,即该位置和其应在的位置
if (i !== nums[i]) return nums[i]
}
return -1 // 没有重复 返回-1
};
o39 数组中出现次数超过一半的数字
/**
* 剑指 Offer 39. 数组中出现次数超过一半的数字
* 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
* 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
* https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/
*/
/**
* @param {number[]} nums
* @return {number}
* 思路:思路很奇特
* 如果一个数大于一半,这个数最后的数量肯定大于其他所有数的数量之和
* 如果当前数是所求数,count++;不是所求数,则count--
* 用非所求数来消耗所求数,消耗不完,最后剩下的数就是所求数
* 时间复杂度:O(n) 空间复杂度:O(1)
*
* y总说:创造一个新解法比回忆起一个解法难一万倍!要多刷题!
*/
var majorityElement = function(nums) {
let count = 0, value = -1
for (let x of nums) {
// 如果count===0,记录value,count++
if (!count) {
count ++
value = x
} else {
// count!==0 此时value值存在,判断value是否等于当前x,等于count增加,否则count消耗
if (value === x) count ++
else count --
}
}
return value
};