【代码随想录训练营】【Day02】第一章|数组|977.有序数组的平方|209.长度最小的子数组|59.螺旋矩阵II|总结
977. 有序数组的平方
题目详细:LeetCode.977
解这道题的思路和方法有很多,最简单的方法就是计算出数组中每个元素的平方数,并记录在新数组中,最后对新数组进行排序即可得到答案,但这个方法效率不高,所以在这里我们讨论一种时间复杂度为 O(n) 的算法来解决本问题。
首先,由题意可知:
- 输入的整数数组 nums 是
非递减顺序
排序的(即有序的、递增的) - 返回
每个数字的平方
组成的新数组- 负数的平方数为正数
- 正数的平方数为正数
通过以上的信息易知,假如我们按从小到大的顺序,依次计算每个数组元素的平方数后,是无法保证新数组依旧是有序的,且此做法并没有利用到数组nums是有序的这一特点。
那么如何去利用nums数组是有序的这一特点呢?
当我们按顺序计算数组中每个元素的平方数后,根据nums数组有序的特点可以发现,其新数组的元素分布有两边大中间小/依旧有序
的特点,根据这一特点我们可以设计一个辅助数组和两个指针(双指针):
- 定义一个与原数组相同大小的辅助数组,并定义一个指针指向数组的尾部(指向尾部保证结果递增,指向头部则保证结果递减)
- 定义一个左指针从小端开始,依次计算每个元素的平方数
- 定义一个右指针从大端开始,依次计算每个元素的平方数
- 比较左右两个指针得到的平方数大小,为了保证新数组是非递减顺序排序的
- 将较大的平方数赋给辅助数组当前指针指向的位置,并移动已赋值的指针像另一端前进
- 在每一次比较后,都能够保证辅助数组是递增的,辅助数组的指针左移一位
- 直到左右两个指针相遇,表示原数组遍历完毕,结束循环
- 最终得到的辅助数组作为结果返回,时间复杂度 O(n)
Java解法(辅助数组 + 双指针):
class Solution {public int pow(int n){return n*n;}public int[] sortedSquares(int[] nums) {int n = nums.length, l = 0, r = n-1;// 定义一个与原数组相同大小的辅助数组int[] res = new int[n];// 定义一个指针指向数组的尾部(指向尾部保证结果递增,指向头部则保证结果递减)int p = n - 1;while(l <= r){int l_val = pow(nums[l]);int r_val = pow(nums[r]);if(l_val > r_val){res[p] = l_val;l++;}else{res[p] = r_val;r--;}p--;}return res;}
}
- 本来是想实现一个不需要辅助数组,仅利用双指针实现原地修改,并得到预期结果的算法,但经过力扣多个测试用例后发现,这个理想的算法需要输入的数组满足两边大中间小且无重复数值或者非负递增序列的需求。
- 虽然可以利用一些逻辑处理来对样本进行预处理以满足需求,但在代码量和逻辑方面也会变得繁琐,所以在绞尽脑汁一个半小时之后,还是选择利用辅助数组来解题。
空间换时间,有时候又未尝不可呢
209.长度最小的子数组
题目详细:LeetCode.209
由题可知:
- 满足条件的
子数组的长度至少为1,最大长度为输入数组的长度
- 子数组是
连续的
因此,首先我们可以:
- 定义左右两个指针来表示一个滑动窗口的左端和右端,两个指针的下标都从0开始
- 利用“左右两个指针的绝对值的差+1”可以表示窗口的长度(也可以定义一个变量,记录窗口的长度,初始化为长度1)
- 定义一个变量,记录窗口中累计的数值大小,初始化为下标为0的数值大小
- 定义一个变量,保持记录满足条件的最小窗口长度,初始化为最大值
紧接着定义一个循环来遍历原数组:
- 当窗口中累计的数值大小 < 目标值时,右端指针向右移动,增加窗口中累计的数值大小
- 当窗口中累计的数值大小 >= 目标值时,计算和比较当前窗口的长度与最小窗口长度变量的大小,并使变量始终记录着最小的窗口长度,之后左端指针向右移动,减小窗口中累计的数值大小
- 当右指针超过原数组边界时,表示原数组已遍历完毕,结束循环
最后返回记录最小窗口长度的变量即可
Java解法(滑动窗口):
class Solution {public int getMin(int a, int b){return a < b ? a : b;}public int minSubArrayLen(int target, int[] nums) {int l = 0, r = 0, sum = nums[l], ans = 100001, n = nums.length;while(l <= r){if(sum >= target){// 当窗口中累计的数值大小 >= 目标值时,计算和比较当前窗口的长度与最小窗口长度变量的大小int size = r-l + 1;// 并使变量始终记录着最小的窗口长度ans = getMin(ans, size);// 之后左端指针向右移动,减小窗口中累计的数值大小sum -= nums[l++];}else{// 当右指针超过原数组边界时,表示原数组已遍历完毕,结束循环if(r+1 == n) break;// 当窗口中累计的数值大小 < 目标值时,右端指针向右移动,增加窗口中累计的数值大小sum += nums[++r];}}return ans!=100001 ? ans : 0;}
}
- 在本解法中,可以看到有一个思路中没有提及到的循环条件
while(l <= r)
,通过该循环条件利用了结果的特点,即长度最小为1
的特点,例如循环一开始窗口内累计的数值大小就满足了目标值,其窗口长度为1,已经是最小长度了,也就不需要后续再滑动窗口继续计算了 - 循环体内会继续将左指针往右移,也就超过了右指针,不满足循环条件,结束循环。
59.螺旋矩阵II
题目详细:LeetCode.59
这道题我是想不出什么技巧,虽然我的写法比较繁琐但容易理解,网上有更加简洁的答案,不过这是一道模拟题,殊途同归,都是同一种思路:
我是这样定义变量的:
- step:表示当前填充的数值
- goal:表示最大的填充数
- out_l = 0, out_r = n-1, out_up = 0, out_down = n-1;
- 定义了这四个变量,来表示当前螺旋矩阵未被填充数据的边界
- int dir = 1; // 右=1,下=2,左=3,上=4
- 定义了一个变量,用于表示当前填充的方向
- 以step > goal作为循环的结束条件,依照dir的方向,按顺时针的方式依次填充螺旋矩阵
class Solution {public int[][] generateMatrix(int n) {int[][] ans = new int[n][n];int i = 0, j = 0, step = 1, goal = n*n;int out_l = 0, out_r = n-1, out_up = 0, out_down = n-1;int dir = 1; // 右=1,下=2,左=3,上=4while(step <= goal){ans[i][j] = step++;// System.out.println("i=" + i + ",j=" + j + ",step=" + (step-1));switch(dir){case 1:if(j == out_r){dir = 2;out_up++;i++;}else{j++;}break;case 2:if(i == out_down){dir = 3;out_r--;j--;}else{i++;}break;case 3:if(j == out_l){dir = 4;out_down--;i--;}else{j--;}break;case 4:if(i == out_up){dir = 1;out_l++;j++;}else{i--;}break;}}return ans;}
}
总结
训练营的第二天,很开心自己能坚持下来,也坚持写文章和做题,在解题过程中,我发现先写文章后做题的效率比我直接做题更高一些,在写文章的过程中,不仅能够回顾之前落下的知识点,也可以使自己的思想更加的灵活且缜密。
平时遇到一些简单的题目的时候,并不会有想法去写一篇文章记录自己思考的过程或者算法的实现思路。但经过这两天的行动发现,有时候简单的题目不是因为它够简单,而是因为它够基础,能够为后面越来越难的题目打下稳固的基础,不至于看到一道难题时手忙脚乱。
从数组这一章节,我在实现算法时,学习到的有数组理论基础、数组的遍历以及对循环算法的巩固。主要运用到的算法技巧有双指针思想(相向指针、快慢指针)和滑动窗口(也是基于双指针实现)。
相信在以后遇到数组相关的算法题或者实际应用场景时,这些算法思想将会是解决问题的关键思想。
最后也是用一句诗来作结,激励自己:
学而不思则罔,思而不学则殆。
【代码随想录训练营】【Day02】第一章|数组|977.有序数组的平方|209.长度最小的子数组|59.螺旋矩阵II|总结相关推荐
- 代码随想录算法训练营第二天|LeetCode 977.有序数组的平方 、209.长度最小的子数组 、59.螺旋矩阵II
LeetCode 977.有序数组的平方 题目链接:977.有序数组的平方 思路: 1.先对每个数进行遍历平方,并插入新的容器中 2.对容器进行排序,返回就可以了 缺陷:开辟了新的容器空间 class ...
- 209. 长度最小的子数组(中等 数组 滑动窗口)
209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, -, n ...
- 代码随想录算法训练营第二天 | LeetCode977有序数组的平方 、209长度最小的子数组、 59.螺旋矩阵II
--------------------------- 977.有序数组的平方 #include <iostream> #include <algorithm> #includ ...
- 10. Leetcode 209. 长度最小的子数组 (数组-同向双指针-滑动窗口)
给定一个含有 n 个正整数的数组和一个正整数 target .找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr ...
- 代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II。
代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II. 977.有序数组的平方 209. 长度最小的子数组 59. 螺旋矩阵 II 977.有序数组的 ...
- 代码随想录算法训练营第二天|leetcode 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
leetcode 977.有序数组的平方 想到昨天写的双指针,十分刻意用了一下,感觉还是比较生疏,还得加强练习和思考,然后发现还需要排序,想到了vector的排序sort(),但是觉得直接用不好,也忘 ...
- 代码随想录算法训练营第二天 | 力扣977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II
代码随想录算法训练营第二天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II 977.有序数组的平方 题目链接:有序数组的平方 题目描述: 给你一个按 非递减顺序 排序的整 ...
- 代码随想录算法训练营第二天| 977有序数组平方、207最小子数组、59螺旋矩阵II。
977.有序数组的平方 力扣题目链接 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序. 示例 1: 输入:nums = [-4,-1, ...
- Leonard代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II。
第一章数组 (今日任务) 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,总结 建议大家先独立做题,然后看视频讲解,然后看文章讲解,然后在重新做一遍题,把题目AC,最后整理 ...
最新文章
- 深度强化学习的前景:帮助机器掌控复杂性
- 解决linux mysql命令 bash: mysql: command not found 的方法
- Notice: Undefined variable解决办法
- VGG16关于学习率如何影响精度效应
- mysql字段为空 不作为查询条件_Mysql基本语法知识点小结
- matlab使用_重磅!哈工大、哈工程无法使用 MATLAB 软件
- oracle表访问方式
- 752. [BJOI2006] 狼抓兔子
- ADO.Net 数据库访问技术
- 如何利用Arcmap模型构建器处理NC格式数据
- docker: 使用nginx容器运行html静态网页以及制作镜像
- 腾讯是如何一刀刀,在15年间干死那些竞争对手的?! (zz)
- mysql 省份城市县区数据表SQL(包含经纬度)
- 微信小程序云开发 操作数据库-数据的批量更新
- 56-OvR 和 OvO
- IMX6UL eMMC命令分析
- 隐藏攻击面,提升信息安全防范能力
- 商用室内机器人才是未来机器人开发的热点与趋势
- 手把手教你脑电波采集及信号处理分析
- Java 教程 —— 开天辟地