Leetcode 977.有序数组的平方
题目:977. 有序数组的平方
初始思路
暴力解法就是先把数组元素全被平方,然后排序即可,时间复杂度取决于排序算法的复杂度。
代码
// 暴力解法
var sortedSquares = function (nums) {
for (let i = 0; i < nums.length; i++) {
nums[i] = nums[i] * nums[i]
}
nums.sort((a, b) => { return a - b })
return nums
};
// 双指针法
var sortedSquares = function (nums) {
let res = new Array(nums.length).fill(0)
let left = 0
let right = nums.length - 1
let index = nums.length - 1
while (left <= right) {
let n1 = nums[left] * nums[left]
let n2 = nums[right] * nums[right]
if (n1 < n2) {
res[index] = n2
index--
right--
} else {
res[index] = n1
index--
left++
}
}
return res
}
感想
- 暴力解法必要时还是要使用。
- 因为数组是有序的,如果原数组有正负数的话,平方后的最大值就在原数组的两端,中间的0肯定是最小的,用双指针从两侧夹。全是负数或者正数的时候也成立。
Leetcode 209.长度最小的子数组
题目:209. 长度最小的子数组 讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
初始思路
之前没做过滑动窗口的题目,完全没思路,先看了视频讲解,十分清晰。
代码
var minSubArrayLen = function (target, nums) {
const len = nums.length
let left = right = sum = 0
let result = Infinity
// left是滑动窗口起始位置,暂时不动
// right向右移动找到符合条件的区间
while (right < len) {
// 先求出这段区间的和
sum += nums[right++]
while (sum >= target) {
// 如果满足条件,求出这段区间的长度
result = Math.min(result,right - left)
// 滑动窗口起始位置开始向左移动,缩小区间
// 如果sum一直大于target就可以一直缩小区间
// 如果小于target了right就向右移动,扩大区间
sum -= nums[left++]
}
}
return result === Infinity ? 0 : result
};
感想
- 首先将窗口起始位置固定,然后right指针向右移动,找到和大于等于target的区间。
在这个区间内部,移动left指针,将区间缩小,如果区间比如原来的长度小就更新结果。
一旦sum小于target,right指针再次右移,找到符合的区间继续收缩。
- 在求区间长度的时候很容易出错,right - left到底要不要加一。
- 时间复杂度:O(n)
空间复杂度:O(1)
- 滑动窗口很有意思,需要多练练。
Leetcode 59.螺旋矩阵II
题目:59. 螺旋矩阵 II 讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
初始思路
乍一看很简单,不就是一圈圈的赋值嘛,但是写起来很复杂, 不知道如何控制循环,控制赋值。不是翻转矩阵那种找关系的题目,单纯就是一圈圈的赋值。就是暴力解法的思路
代码
// 采用左闭右开
var generateMatrix = function (n) {
// 起始位置
let startX = startY = 0
// 循环次数
let loop = Math.floor(n / 2)
// 中间位置 就是n^2在的位置
let mid = Math.floor(n / 2)
// 控制每一层填充元素的个数
let offset = 1
// 填充的数字
let count = 1
// 申请一个二维数组
let res = new Array(n).fill(0).map(() => new Array(n).fill(0))
while (loop--) {
let row = startX
let col = startY
// 上 col逐渐变大
for (; col < startY + n - offset; col++) {
res[row][col] = count++
}
// 右 row逐渐变大
for (; row < startX + n - offset; row++) {
res[row][col] = count++
}
// 下 col从大变小
for (; col > startY; col--) {
res[row][col] = count++
}
// 左 row从大变小
for (; row > startX; row--) {
res[row][col] = count++
}
// 更新起始位置 放到下一圈矩形的左上角
startX++
startY++
// 到下一次内圈,一行元素减少两个
offset += 2
}
// 如果n为奇数,要给n^2单独赋值
if (n % 2 === 1) {
res[mid][mid] = n * n
}
return res
};
感想
- 起始位置startX、startY循环完一圈后都加一,左上角就是下一圈的起始位置。
- 因为左闭右开,所以每行填充元素个数是 n - offset。控制每行元素个数的offset循环完一圈之后减二。
- 在一圈的运行过程中:col变大 ——> row变大 ——> col回到起始位置 ——> row回到起始位置
- 最后需要判断一下中心位置需不需要额外填。