977.有序数组的平方
题目:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
思路:
只能想到暴力解法,先平方后排序。
代码:
var sortedSquares = function(nums) {
const newNums = nums.map(el=>el*el)
function stb (a,b) {
return a-b
}
newNums.sort(stb)
return newNums
};
优化:
看了文章的双指针解法思路:因为原数组是有序排列的,但是因为要平方,所以不确定负数和正数的平方值大小,因此在原数组头尾分别添加一个指针,比较平方后大小按顺序放入新数组中。
代码:
// 自己写
var sortedSquares = function (nums) {
const newNums = new Array(nums.length)
let i = 0, j = nums.length - 1, k = nums.length-1
while (k >= 0) {
if (nums[i] * nums[i] < nums[j] * nums[j]) {
newNums[k--] = nums[j] * nums[j]
j--
} else {
newNums[k--] = nums[i] * nums[i]
i++
}
}
return newNums
};
// 看大佬
var sortedSquares = function(nums) {
let n = nums.length;
let res = new Array(n).fill(0);
let i = 0, j = n - 1, k = n - 1;
while (i <= j) {
let left = nums[i] * nums[i],
right = nums[j] * nums[j];
if (left < right) {
res[k--] = right;
j--;
} else {
res[k--] = left;
i++;
}
}
return res;
};
总结:
当要求时间复杂度为 O(n) 或者原地修改数组的时候可以使用双指针法,即本来需要两次循环完成的操作,通过双指针法一次循环解决问题。
209.长度最小的子数组
题目:
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 \[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
思路:
设置两个指针,第一个指针遍历数组中的每一个值,第二个指针动态遍历,计算出每次第一个指针所指的值到第二个指针所指的值的累加和,和目标值进行比较,如果大于等于目标值就对当前子数组长度进行比较,如果小于上一个子数组长度就记录该值,子数组长度初始值是数组长度。
同时对两种情况分别处理:
- 如果数组中所有值的累加和小于目标值直接返回0
- 如果数组中单个值的长度大于等于目标值直接返回1
代码:
自己写的错误代码
var minSubArrayLen = function (target, nums) {
let min = nums.length
if (nums.reduce((prev,cur)=>prev+cur)<target) return 0
for (let i = 0; i < nums.length; i++) {
if (nums[i]>=target) return 1
if (i<nums.length-1) {
for (let j = i; j < nums.length; j++) {
let index = nums.slice(i, j + 1).reduce((prev, cur) => prev + cur)
console.log(index)
if (index >= target) {
min = (j - i + 1) > min ? min : (j - i + 1)
break
}
}
}
}
return min
};
优化:
看了代码随想录文章才知道自己的思路实际上是双循坏暴力解法,看完移动窗口思路以后仍然写不出正确的代码,于是看了一下大佬的解法。
思路是声明两个指针,第二个指针依次遍历数组中的值,计算出当前窗口内的和,如果窗口内的和大于等于目标值,就取当前窗口长度和初始窗口长度(值为无限)进行比较,取小的那一个,然后将第一个指针向后移一位,窗口内的和减去第一个指针所指的值。最后对窗口长度进行判断,如果是初始设置的无限(即数组内没有窗口的和满足要求)就返回0,否则返回得到的最小窗口的长度。
代码:
var minSubArrayLen = function (target, nums) {
let sum = 0, subLength = Infinity,i,j
i=j=0
while (j<nums.length) {
sum+=nums[j]
while (sum>=target){
subLength = Math.min(subLength,j-i+1)
sum-=nums[i++]
}
j++
}
return subLength === Infinity?0:subLength
};
总结:
第一个看完思路仍然写不出的题目,看了大佬的解法,能理解逻辑,并且学到了Infinity这个值,希望自己下次遇到该类问题可以解决。
59.螺旋矩阵II
题目:
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
思路:
没有思路
代码:
写不出来
优化:
看了代码随想录的思路后,还是弄不明白如何判断内层循环的数量,不知道怎么设置循环上限。看了卡哥的视频以后,理解了逻辑,下面给出我的思路。
首先分别设置行和列的起始指针startX、startY为0;设置一个循环层数loop=n/2,如果n为奇数在最后单独在中心填入一个值;设置一个索引index表示当前的循环层数;设置一个填入数字的初始值count=1。
设置一个外侧循环,判断条件是当前循环层数index是否小于总循环层数,在循环内部设置一个每层循环要填入的数字个数为n-offset,offset是当前循环层数index+1。然后设置四次循环,分别将数据填入正方形的四个边。然后将行和列的起始指针+1,将当前层数index+1。
代码:
var generateMatrix = function (n) {
const arr = new Array(n).fill(0).map(() => new Array(n).fill(0))
let startX, startY, index, count = 1, loop = Math.floor(n / 2)
startX = startY = index = 0
while (index < loop) {
let offset = index + 1
let i = startX, j = startY
for (; j < n - offset; j++) {
arr[i][j] = count++
}
for (; i < n - offset; i++) {
arr[i][j] = count++
}
for (; j > startY; j--) {
arr[i][j] = count++
}
for (; i > startX; i--) {
arr[i][j] = count++
}
startX++
startY++
index++
}
if (n % 2 === 1) {
arr[loop][loop] = n * n
}
return arr
};
总结:
这道题理解以后其实不难,但是也是我第一次一点思路也没有的题,一开始觉得直接暴力填入,后来怎么想怎么不对,看完代码随想录左闭右开的思路以后有点感觉,但是上手一写又觉得后面的上限无法设置,但是最后看完视频也确实自己写出来了。
Day2总结:
第二天的题其实不难,但是自己算法能力实在太差,已经要花很长时间去思考,并且已经无法独立写出来,但是我会放平心态,毕竟自己算法基础薄弱,在60天的训练营结束以后,自己也会二刷三刷,希望自己可以拿下算法,对于前端方向的自己来说,掌握这些算法思想为也以后的工作打下的很好的基础。