代码随想录day02
977.有序数组的平方
解题思路
数组平方的最大值就在数组的两端.
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
代码
- 暴力解法 复杂度O(nlogn)
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
//先求平方再排序 复杂度O(nlogn)
nums = nums.map((item => {
return item*item
}))
return nums.sort((a,b) => (a-b)) //
};
2.双指针法,复杂度O(n)
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
let len = nums.length
let k=len-1
let result = new Array(len).fill(0)
for(let i=0,j=len-1; i<len&j>=0&i<=j;) {
if(nums[i]*nums[i] > nums[j]*nums[j]) {
result[k--] = nums[i]*nums[i]
i++
} else {
result[k--] = nums[j]*nums[j]
j--
}
}
return result
};
209.长度最小的子数组
解题思路–滑动窗口
1.使用滑动窗口来解决使用一个for循环解决两个for循环的事情,本质上也是使用两个指针。
2.只用一个指针j,代表的是终止位置(注意不是起始位置)
3.起始位置需要用一个动态移动的策略来移动位置
代码
- 暴力解法 复杂度O(n^2),超时了不行!!
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
let result = Infinity;
for(let i=0;i<nums.length;i++) {
for(let j=i;j<nums.length;j++) {
let count = 0
for(let p=i; p<=j; p++) {
count += nums[p]
}
if(count >= target) {
result = Math.min(result,j-i+1)
}
}
}
return result===Infinity ? 0 : result
};
2.滑动窗口,复杂度O(n)
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
let result = Infinity;
let i=0 // 滑动窗口起始位置
let sum=0 // 滑动窗口数值之和
let subLength=0 // 滑动窗口的长度
for(let j=0;j<nums.length;j++) {
sum += nums[j]
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
while(sum >= target) {
subLength = j-i+1 // 取子序列的长度
sum -= nums[i++]
result = Math.min(result,subLength) // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result===Infinity ? 0 : result
};
重点和收获
1.所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果,用一个for循环来做2个for循环所做的事情。
2.滑动窗口解题的关键:窗口的起始位置如何移动?
就是当我们发现集合里面所有的元素和 >= target,我们再去移动起始位置,这样就实现了动态调整起始位置,来去收集不同长度区间里面的和。
59.螺旋矩阵
解题思路
1.本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
2.注意节点的边界处理,坚持左闭右开的原则
3.首先确定每个循环转几圈呢?n/2圈数??因为n是边长,除以2之后就是圈数。还需要判断n是否是奇数,如果是奇数的话要把最后遍历的值赋给它
4.定义每循环一个圈的起始位置startx = 0, starty = 0
5.需要控制每一条边遍历的长度,每次循环右边界收缩一位offset=1
6.开始转圈赋值
7.每转一圈,起始位置startx和starty要加一
代码
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function(n) {
let result = new Array(n).fill(0).map((item => {return new Array(n).fill(0)}))
let startX = startY = 0 // 起始位置
let offset = 1 // 控制每一层填充元素个数
let count = 1 // 更新填充数字
let loop = ~~(n/2) // 旋转圈数
let mid = ~~(n/2) // 中间位置
while(loop--) {
let i = startX
let j = startY
// 下面开始的四个for就是模拟转了一圈
// 模拟填充上行从左到右(左闭右开)
for(; j<n-offset; j++) {
result[i][j]=count++
}
// 模拟填充右列从上到下(左闭右开)
for(; i<n-offset;i++) {
result[i][j]=count++
}
// 模拟填充下行从右到左(左闭右开)
for(;j>startY;j--) {
result[i][j]=count++
}
// 模拟填充左列从下到上(左闭右开)
for(;i>startX;i--) {
result[i][j]=count++
}
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startX++
startY++
// offset 控制每一圈里每一条边遍历的长度
offset++
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2) {
result[mid][mid] = count;
}
return result
};
重点和收获
1.定义一个二维数组:
let result = new Array(n).fill(0).map((item => {return new Array(n).fill(0)}))
2.关于offset不太好理解:offset的意义在于 结束一圈后 起始位置向后移 结束位置向前移。