代码随想录训练营第二天
leetcode 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II
977.有序数组的平方
977有序数组的平方
看到题的思路
初看到这道题的时候,想到排序也可以做。但是不用排序应该怎么做。
首先初始的数组是从小到大排序的。有正数也有负数。负数的平方会大于正数的平方,这取决于绝对值的大小。
那么怎么保证平方后数组仍能从小到大排序呢
这时候想到两个指针,头尾各一个。平方后比较大小。
创建一个ans数组装平方排序后的数值。大的值放到数组的后面。从后到前填充数组。同时指针变动。小的那个指针不变。
这样扫一圈就可以得到最终的答案。同时也要注意循环停止条件。
代码
class Solution {
public int[] sortedSquares(int[] nums) {
int len=nums.length;
int []ans=new int[len];
int k=len-1;
for(int i=0,j=len-1;i<=j;)
{
if(Math.pow(nums[i],2)>=Math.pow(nums[j],2))
{
ans[k]=(int)Math.pow(nums[i],2);
i++;
}
else
{
ans[k]=(int)Math.pow(nums[j],2);
j--;
}
k--;
}
return ans;
}
}
209.长度最小的子数组
209 长度最小的子数组
看到题的思路
看到这题,首先的想法就是暴力。o(n^2)。但是这种会超时。
那么怎么才能简单的找到最小子数组呢?
后来想到前置和:[2,3,1,2,4,3] 的前置和数组就是[0,2,5,6,8,12,15]。
前置和代表着前n位的数值之和。前面添0是为了方便算相邻子数组的个数。比如12-5=7=target 12的index=5,5的index=2;相减等于3。也就是3个子数组的和 。即1,2,4的和。
然后用快慢指针,快指针对应的值减去慢指针对应的值,大于target就是满足题意。记录此时快慢指针之间的距离。更新最小距离。如果一直大的话。就不断地更新慢指针,直到相减小于target。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int len=nums.length;
int[] ans=new int[len+1];
ans[0] =0;
for(int i=1;i<=len;i++)
{
ans[i]=ans[i-1]+nums[i-1];//前置和
}
int min=Integer.MAX_VALUE;
for(int i=0,j=0;j<=len;)
{
while(ans[j]-ans[i]>=target)//大于target时候不断更新慢指针
{
min=Math.min(j-i,min);
i++;
}
j++;
}
return min==Integer.MAX_VALUE?0:min;
}
}
不过这道题题解是用的滑动窗口。利用i j快慢两个指针不断调整窗口的区间。
i是慢指针,j是快指针
什么时候需要调整指针位置呢?
i先不移动。j不断移动直到i到j区间的和>=target。记录指针间距,更新最小子区间长度。
但是此时我们没办法保证当前j为尾时该区间长度最小。现在i应该向前走一步。我们需要判断i+1这个位置到j的和是不是也大于target?如果是的话,那继续更新最小子区间长度。直到j到i这中间的和小于target为止。
下一次就是快指针j再向前走一步。判断此时i到j的是否大于等于target。重复以上环节…
代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n=nums.length;
if(n==0)
{
return 0;
}
int ans=Integer.MAX_VALUE;
int start=0,end=0;
int sum=0;
while(end<n)
{
sum+=nums[end];
while(sum>=target)
{
ans=Math.min(end-start+1,ans);
sum-=nums[start];
start++;
}
end++;
}
return ans==Integer.MAX_VALUE?0:ans;
}
}
59.螺旋矩阵II
59 螺旋矩阵Ⅱ
看到题的思路
这个题真的就是要先理清思路,该从哪里下手。
我们要先确定我们应该怎么将1~n*n这些数字填充到二维数组中。
既然他是螺旋分布,那我们就得螺旋着去填充。每螺旋一层为一次循环。我们需要几次循环。答案是n/2;对于奇数来说最终中间会剩一个。那我们就直接在最后处理这个数就行。
每次螺旋转一圈,有四条边。我们需要处理好四个角也就是边界区域。
拿n=4来说。在最外一圈 我们是每次填充123还是1234。这四条边应该有同一的规则所以我们应该是先123 然后456 然后 789 最后10 11 12 也就是相当于是左闭右开。头闭尾开
代码
class Solution {
public int[][] generateMatrix(int n) {
int startx=0;
int starty=0;
int offset=1;
int count=1;
int[][]a=new int[n][n];
int time=n/2;
int j=0,i=0;
while(time!=0)
{
for( j=starty;j<n-offset;j++)
a[startx][j]=count++;
for(i=startx;i<n-offset;i++)
a[i][n-offset]=count++;
for(;j>startx;j--)
a[n-offset][j]=count++;
for(;i>starty;i--)
a[i][startx]=count++;
offset++;
startx++;
starty++;
time--;
}
if(n%2!=0)
{
a[n/2][n/2]=n*n;
}
return a;
}
}
今日收获
今天的题目比昨天的难了!通过这几道题加深了双指针的理解,能够更好的应用在题目当中。还学会了滑动窗口,动态的解决问题。螺旋矩阵这个题虽然没涉及到别的算法知识,但是要理清思路,注意条件。