977.有序数组的平方
这道题给出的原数组有两个特点:
1、由小到大
2、有负数有正数
因此,这个数组平方后的数应该是从两头向中间的0减小的,但是两头的大小需要我们用两个指针便历之后去判断大小。在遍历的同时left指针向右走,right指针向左走,每次判断left和right指针指向的平方数的大小,哪边大就将这个大的数放到新的数组中,注意:题目要求新数组由小到大排列,所以我们也要由最后往前面放平方数。 每次判断大小,如果是left指针的平方数大,left右移一位;如果是right指针的平方数大,right左移一位,直到right=left,为什么要等于?因为当right=left的时候,它们同时指向的这个平方数还没有被放到新数组里,因此要判断一次大小(当然是一样大的)再将这个数放到新的数组中。
可以举一个很简单的例子: 当原数组只有两个元素的时候,left=0,right=1,两个指针判断玩大小只会把一个指针指向的平方数放到新数组中,还有一个还没放,因此还需要再移动一下指针,再放一次。
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0;
int right = nums.length - 1;
int[] numsRes = new int[nums.length];
int i = nums.length - 1;//这个i用来控制放入新数组的位置,无论是左右指针哪一个更新,i都需要--
while(left <= right){//注意这里的等于也是有含义的,假设整个数组就两个数,那么left = right,也需要进行一次while循环
if(nums[left]*nums[left] >= nums[right]*nums[right]){
numsRes[i] = nums[left]*nums[left];
i--;
left++;
}else{
numsRes[i] = nums[right]*nums[right];
i--;
right--;
}
}
return numsRes;
}
}
59.螺旋矩阵||
这道题目根据题意,需要创建一个int[n][n]的数组,然后按照题目顺时针的顺序将[1,n**2]的数字放到这个数组中,所以关键在于确定每个数放置的位置的索引值,以控制数是顺时针放置在数组中的。
如图所示,我们放置的整体顺序是一圈一圈的,每个圈四个边,每个边有起始位置用start参数控制,每一圈中每个边遍历的个数不同,因此用offset控制,offset如图所示往里一圈+2,start如图所示往里一圈+1。
一共应该是(int)n/2圈,如果n是奇数的话最中间的是单独的一个元素,需要单独给值,我们最后判断一下n就行了,赋个值。
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];//存储结果数组
int offset = 1;//控制不同圈每个边遍历的个数
int start = 0;//控制不同圈每个边起始索引
int num = 1;//控制要放入的值
for(int i = 0;i < n/2;i++){//圈数
for(int k = 0;k < n-offset;k++){//上边
res[start][k+start] = num;
//如图上边的x不变为start,y从start往后共遍历n-offset个元素
num++;
}
for(int k = 0;k < n-offset;k++){//右边
res[start+k][n-1-start] = num;
//如图右边的y不变为n-1-start,x从start往后共遍历n-offset个
num++;
}
for(int k = 0;k < n-offset;k++){//下边
res[n-1-start][n-1-start-k] = num;
//如图下边的x不变为n-1-start,y从n-1-start开始往前共遍历n-offset个,因此为减
num++;
}
for(int k = 0;k < n-offset;k++){//左边
res[n-1-start-k][start] = num;
//如图左边的y不变为start,x从n-1-start开始往前遍历共遍历n-offset个,因此为减
num++;
}
start++;//遍历完一圈start加一
offset+=2;//遍历完一圈offset加2
}
if(n%2 == 1) res[n/2][n/2] = n*n;//n偶数的话正好遍历n/2圈,n为奇数的话最中间的这个元素需要单独赋值
return res;
}
}
209.长度最小的子数组
暴力解法
当然超出了时间限制,这里讲解一下思路:
定义两个指针left和right,初始化为0。left标定之后,right向后遍历,只要left或者right指针动一次,就计算[left,right]区间里的和sum。
如果sum>=target,left++以减少sum;
如果sum<target,right++以增加sum;
while()循环用right<nums.length条件控制,left永远小于right。
最后如果left0并且rightlength,说明整个数组的和都达不到target,返回0.
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int right = 0;
int res = nums.length;
while(right < nums.length){
int sum = 0;
for(int i = left;i <= right;i++){
sum += nums[i];
}
if(sum >= target){
res = Math.min(res,right-left+1);
left++;
}else{
right++;
}
}
if(left == 0 && right == nums.length) return 0;
return res;
}
}
209.滑动窗口
这个方法需要两个指针i和j控制滑动窗口的头和尾,尾指针需要遍历整个数组,i指针用来当j指针滑动到符合条件的区间的尾的时候,调整区间的头从而缩小滑动窗口的区间以获得最小的区间。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int i = 0;
int res = nums.length;
int total = 0;
for(int j = 0;j < nums.length;j++){
total += nums[j];
sum+=nums[j];
while(sum >= target){//当遇到符合条件的区间的时候,需要去持续缩小该区间的范围直到找到最短的符合条件的区间,所以这里用while不用if
res = Math.min(res,j-i+1);//每次缩小范围之后去获取一下这个最小范围的区间长度
sum -= nums[i];//sum减去缩小的nums[i]的值
i++;//头指针右移
}
}
if(total < target) return 0;//在遍历的过程中,也同时获取到了整个数组的和,如果整个数组的和都小于target了,则说明该数组不存在满足条件的子数组,因此返回0.
return res;
}
}