Leetcode 977. 有序数组的平方
思路
这道题的意思很简单,暴力解法很容易想到,直接平方再排序。但是由于时间复杂度过高,我们可以采用双指针的解法。
由于题目中强调数组是非递减顺序排序的, 但考虑到负数平方之后可能成为最大数。所以我们这里的双指针,一个从后向前遍历,一个从前向后遍历。
难点
数组平方的最大值就在数组的两端,不是最左边就是最右边,此时定义两个指针分别为i,j;由i,j指向的元素判断大小,得到新的数组元素的排序。
下面有动画帮助大家理解。
代码(Java)
写法1:暴力解法
时间复杂度: O(n + nlogn)
class Solution {
public int[] sortedSquares(int[] nums) {
for (int i=0;i<nums.length;i++){
nums[i]*=nums[i];//使数组中的每个元素都被自己的平方覆盖
}
Arrays.sort(nums);//将平方后的数组元素重新排序
return nums;
}
}
写法2:双指针法
时间复杂度:O(n)
class Solution {
public int[] sortedSquares(int[] nums) {
int i=0; //前指针i,从前往后遍历
int j=nums.length-1;//后指针j,从后往前遍历
int[] ret=new int[nums.length];//定义新数组
int k=nums.length-1;//新数组的指针,指向元素存放的位置
while (i<=j){
if (nums[i]*nums[i]>nums[j]*nums[j]){ //负数的绝对值大于正数的绝对值
ret[k--]=nums[i]*nums[i];
i++;
}else { //负数的绝对值小于or等于正数的绝对值
ret[k--]=nums[j]*nums[j];
j--;
}
}
return ret;
}
}
代码随想录链接
下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频
Leetcode 209. 长度最小的子数组
思路
可以采用暴力解法,两层for循环嵌套,一层for循环用来控制数组的起始位置,另一层for循环控制数组的终止位置。
两个for循环,也可以用双指针法来解决,分别用两个指针和一个for循环完成。
难点
这道题是一道典型的滑动窗口问题,使用一个for循环时,我们首先确定次循环确定的是数组的起始位置还是终止位置。
如果用来确定起始位置,那么数组的终止位置还是无法确定。
如果用来确定终止位置,那么该指针即用来遍历数组中的元素,当窗口中的元素和 大于目标值时,移动前指针进行窗口的缩小,从而得到满足条件的窗口长度最小值。
下面用动画来帮助大家理解。
代码(Java)
写法1:暴力解法
时间复杂度:O(n^2)
空间复杂度:O(1)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum;
int subLen=0;
int ans= Integer.MAX_VALUE;
for (int i=0;i<nums.length;i++){//外层循环:确定数组的起始位置
sum=0;
for (int j=i;j<nums.length;j++){//内层循环:确定数组的终止位置
sum+=nums[j];
if (sum>=target){
subLen=j-i+1;
ans = Math.min(subLen,ans);
break;
}
}
}
return ans == Integer.MAX_VALUE ? 0:ans;
}
}
写法2:双指针法
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i=0;//前指针i,用来确定滑动窗口的起始位置
int sum=0;
int subLen=0;
int ans=Integer.MAX_VALUE;
for (int j=0;j<nums.length;j++){ //后指针j,用来确定滑动窗口的终止位置
sum+=nums[j];
while (sum>=target){
subLen=j-i+1;
ans=Math.min(subLen,ans);
sum-=nums[i];
i++; //滑动窗口:更新i的位置
}
}
return ans == Integer.MAX_VALUE ? 0:ans;
}
}
}
}
代码随想录链接
下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频
Leetcode 59. 螺旋矩阵II
思路
这道题本身没有强调技术性的算法,需要搞清楚的只有每次读取螺旋矩阵的元素的方法,顺时针读取矩阵中的元素时,每层可以看作四条边。
由于每次读取的起始位置都是正方形的左上角,观察可得横纵坐标相同,即在二维数组中的两个索引数相同。
循环次数,根据观察得到等于n/2。当n为奇数时,中间的数需要再单独补上。
难点
四条边的读取方向可以分为:
- 从左到右➡️
- 从上到下⬇️
- 从右到左⬅️
- 从下到上⬆️
读取每层循环时,如果无规则地读取,很容易扰乱思绪。所以必须要确定边界位置读不读,这里我采用取头舍尾的读法。
代码(Java)
class Solution {
public int[][] generateMatrix(int n) {
int ret[][]=new int[n][n];
int start=0;//读取螺旋矩阵的起始位置
int count=1;//读取到的数字(从1开始依次向后)
int loop=0;//控制循环的次数
int i,j;
while (loop++ < n/2){
//从左到右,此时的纵坐标是统一的,即前索引
for (j=start;j<n-loop;j++){
ret[start][j]=count++;
}
//从上到下,此时的横坐标是统一的,即后索引
for (i=start;i<n-loop;i++){
ret[i][j]=count++;
}
//从右到左,此时的纵坐标是统一的,即后索引
for (;j>=loop;j--){
ret[i][j]=count++;
}
//从下到上,此时的横坐标是统一的,即后索引
for (;i>=loop;i--){
ret[i][j]=count++;
}
start++;
}
if (n%2==1){
ret[start][start]=n*n;
}
return ret;
}
}
代码随想录链接
下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频
总结
今天主要学习了双指针的解法,此解法在数组的算法题中经常用到,该解法最重要的点在于两个指针分别的任务是什么,另外螺旋矩阵问题和二分法问题类似,问题的重点都在于确定循环不变量,左闭右闭或左闭右开,区间的不同也会导致循环不变量的定义不同。