【算法】代码随想录训练营Day2打卡,LeetCode 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II
数组
代码随想录算法训练营Day2任务。
LeetCode 977.有序数组的平方
力扣链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
这道题我们读题, 首先数组是非递减序,要求将数组每一项平方后,再按照非递减序排列。
首先关键词就是数组是非递减序,那么就可以理解为 有序递增 , 而这一道题要求返回的是平方后的非递减序数组,那么我们就要考虑到负数的问题了。
首先这道题最无脑最简单的解法就是循环暴力解啦,我们将每一个数都平方之后再进行排序,这样就完美解决了这个问题,但是暴力解这种方法肯定不是这道题考察的点,他的时间复杂度也更高是O(n+nlogn)
所以我们就要思考是否右更优的解法呢,那么我们可以考虑一下数组中最常用的双指针法,这道题的重点在于负数的平方是正数,可能比某个正数更大,那么快慢指针的双指针法明显是不适用的。
如图

如图我们发现如果使用快慢指针,我们无法快速判断-5的平方和 7 3的平方谁更大,那么怎么能够直接比较呢?看着图我们脑袋灵光一闪,使用首尾指针就可以快速判断,然后我们使用一个新的长度一致的数组用尾插法进行填充。
如图

以此类推 循环条件为 left<=right,当左右指针撞再一起之后结束循环
思路讲完了就来看看代码把
C语言解法
双指针法
int* sortedSquares(int* nums, int numsSize, int* returnSize){
int* res = (int*)malloc(sizeof(int) * numsSize); // 创建一个相同长度的数组;
*returnSize = numsSize;
int left =0;
int right = numsSize-1;
int rt=numsSize-1;
while(left<=right){
if(abs(nums[left])<abs(nums[right])){
res[rt--] = nums[right] * nums[right];
right--;
}
else{
res[rt--] = nums[left] * nums[left];
left++;
}
}
return res;
}
JS解法
- 暴力解
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
let res = [];
for(let i=0;i<nums.length;i++){
res[i] = nums[i] * nums[i];
}
res.sort((a,b)=> a-b);
return res
};
- 双指针法
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
let res = [];
let left = 0 ;
let right = nums.length-1;
let cur = nums.length -1 ;
while(left<=right){
if(Math.abs(nums[left])<Math.abs(nums[right])){
res[cur--] = nums[right] * nums[right];
right--;
}else{
res[cur--] = nums[left]* nums[left];
left++
}
}
return res
};
209. 长度最小的子数组
力扣链接:https://leetcode.cn/problems/minimum-size-subarray-sum/description/
首先我们读题
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。
这道题显而易见可以使用快慢指针来代表我们连续子数组的边界(这种方法也叫滑动窗口)
接下来我们来梳理一下思路。
就用题中的案例 target = 7, nums = [2,3,1,2,4,3]
既然是双指针,那么我们就要先定义一个slot,一个fast 两个指针,并指向0 ,需要一个sum变量来计算我们连续子数组的和,需要一个res来记录我们的最小的子数组的长度,最后返回的也是这个res
我们需要一个循环条件,这个条件则是fast指针要<数组nums的长度,因为是子数组,所以你子数组的右边界是一定不能长于nums数组的右边界的,所以这里的循环条件是 fast<nums.length是很好理解的
而我们将sum的值初始化为数组的第0项 即 sum = nums[0];
因为我们一进入循环体就要判断sum的值;
当sum<target的时候,我们就需要把 fast指针向后移动 且 sum要加上 fast移动后所指的值
当sum>= target的时候 因为我们要寻求最小的子数组长度,所以我们要把slot指针向后移动来缩小边界,所以 slot++ 且 sum要减去slot移动后所指向的值,且 res要取 res所存的值与 当前子数组的长度之中的最小值。
如此到循环结束 我们返回的res就是满足条件的最小连续子数组的长度了
以上解析可根据下图理解

接下来思路理解完毕,我们就要来写代码了
C语言解法
int minSubArrayLen(int target, int* nums, int numsSize){
int res = INT_MAX;
int slot =0;
int fast =0;
int sum = nums[0];
while(fast<numsSize){
if(sum<target ){
fast++;
if(fast<numsSize){ //这里要注意,如果越界取值会报错,所以在这里判断一下是否越界 坑!!
sum += nums[fast];
}
}else{
int curSize = fast-slot+1;
res = res>=curSize ? curSize : res ;
sum -= nums[slot++];
}
}
return res == INT_MAX ? 0 : res;
}
JS解法
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
let res = Infinity;
let slot =0;
let fast =0;
let sum = nums[0];
while(fast<nums.length){
if(sum<target){
sum += nums[++fast];
}else{
res = Math.min(res,fast-slot+1)
sum -= nums[slot++];// 注意slot++一定要放在 计算数组长度的后面哦!
}
}
return res == Infinity ? 0 : res;
};
59. 螺旋矩阵 II
https://leetcode.cn/problems/spiral-matrix-ii/
根据题目来梳理思路,首先我们要做一个n*n的二维数组,
接下来我们要螺旋填入数字1-n^2
那么我们以n=4为例子 画一张图,如果想要有规律的填充就要做到以下的事情

C语言解法
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
//初始化返回的结果数组的大小
*returnSize = n;
*returnColumnSizes = (int*)malloc(sizeof(int) * n);
//初始化返回结果数组ans
int** ans = (int**)malloc(sizeof(int*) * n);
int i;
for(i = 0; i < n; i++) {
ans[i] = (int*)malloc(sizeof(int) * n);
(*returnColumnSizes)[i] = n;
}
int startX = 0;
int startY = 0;
int mid = n / 2;
int loop = n / 2;
int offset = 1;
int count = 1;
while(loop) {
int col = startX;
int row= startY;
for(; col< startX+ n - offset; col++) {
ans[row][col] = count++;
}
for(; row < startY+ n - offset; i=row++) {
ans[row][col] = count++;
}
for(; col > startY; col--) {
ans[row][col] = count++;
for(; row > startX; row--) {
ans[row][col] = count++;
}
offset+=2;
startX++;
startY++;
loop--;
}
if(n%2)
ans[mid][mid] = count;
return ans;
}
JS解法
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function(n) {
let translate = 1;
let startX = startY = 0; //其实位置
let cont = 1 ;
let loop = Math.floor(n/2);
let mid = Math.floor(n/2);
let res = new Array(n).fill(0).map(() => new Array(n).fill(0));
while(loop--){
let row = startY ;
let col = startX ;
for(;col<startX+n-translate;col++){
res[row][col] = cont++
}
for(;row<startY + n - translate;row++){
res[row][col] = cont++
}
for(;col>startX;col--){
res[row][col] = cont++
}
for(;row>startY;row--){
res[row][col] = cont++
}
startX++;
startY++;
translate+=2;
}
if(n%2==1){
res[mid][mid] = cont
}
return res;
};
今日心得
今日完成算法+完成文章的总共时间共3小时,其中长度最小的子数组是印象最深刻的,在自己写的过程中,也通过画图来梳理自己的思路,然后根据画的图来写代码会少走很多弯路,所以我认为这个是一个很好的过程。
数组
对于数组这一块,我在day1时总结了我对数组这个数据结构的基本理解和 我对于JS和c语言中数组的区别的概念。同样的在刷题过程中我也能很明确的感知到脚本语言JS与编译语言C的巨大化的差异,C语言十分的严谨,甚至数组在寻址过程中产生越界会报错,而js只会指向null 并不会报错,所以js在写题的时候有些地方会很偷懒,不用特别严谨。但再用c去复刻js的代码时,就会出现很多问题,在这里也踩过很多坑。
而数组中,我们最常用的就是指针法,快慢指针,滑动窗口,相对指针等等,根据题意思和一些例子,我们通过画图可以快速的决定我们是用哪一种指针法
本文介绍了在LeetCode训练营中解决三个算法问题的方法,包括有序数组的平方的C语言和JS解法,使用双指针法避免排序;长度最小的子数组问题,利用快慢指针实现滑动窗口;以及螺旋矩阵II的构建,通过迭代方式按螺旋顺序填充矩阵。作者强调了画图和理解数据结构在解题过程中的重要性。

1451

被折叠的 条评论
为什么被折叠?



