学习目标:
- 完成有序数组的平方、长度最小的子数组和螺旋矩阵相关题目
学习内容:
977.有序数组的平方
题目:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1: 输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2: 输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]
开始看这题时很容易想到暴力解法,就是将数组中所有元素都平方一下再进行排序。但是这种方法的时间复杂度较大,因此需要采用双指针法。
由于数组中的元素是按大小排列的,所以我们可以发现元素平方后最大的数字总是在最左边或者是最右边。因此我们可以使用两个指针left和right,分别指向数组的开头和结尾,并比较两个元素的大小,将最大的元素放在结果数组的最后面,然后循环使两个指针靠近,并依次比较两个指针所指位置数字平方后的大小,放入结果数组中。实现代码如下:
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0;
int right = nums.length - 1;
int[] array = new int[nums.length];
int len = nums.length - 1;
while(left <= right){
if(nums[left]*nums[left] < nums[right]*nums[right]){
array[len] = nums[right]*nums[right];
len--;
right--;
}
else{
array[len] = nums[left]*nums[left];
len--;
left++;
}
}
return array;
}
}
209.长度最小的子数组
题目:
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
这题同样可以使用暴力解法,使用两个for循环,外层循环指向子序列开始位置,内层循环指向子序列结束位置,这样就可以将开始位置到结束位置元素加起来,并将结果与s相比较。但是这个时间复杂度为O(n^2)。
因此为了减小时间复杂度,可以采用滑动窗口这个思想。滑动窗口外层循环指向子序列结束位置,内层循环指向子序列开始位置,不要以为for里放一个while就以为是O(n^2),主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。代码如下:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int left = 0;
int result = Integer.MAX_VALUE;
for(int right=0; right<nums.length; right++){
sum = sum + nums[right];
while(sum >= target){
result = Math.min(result, right-left+1);
sum = sum - nums[left];
left++;
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
其中,Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
59.螺旋矩阵II
题目:
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
这题需要注意的是循环的边界设置问题,在写代码时最好画个矩阵,根据矩阵的边界设置各个参数。代码如下:
class Solution {
public int[][] generateMatrix(int n) {
int loop = n/2;
int startx = 0;
int starty = 0;
int count = 1;
int offset = 1;
int i,j;
int[][] nums = new int[n][n];
while(loop>0){
for(j=starty; j<n-offset; j++){
nums[startx][j] = count++;
}
for(i=startx; i<n-offset; i++){
nums[i][j] = count++;
}
for(; j>starty; j--){
nums[i][j] = count++;
}
for(; i>startx; i--){
nums[i][j] = count++;
}
startx++;
starty++;
offset++;
loop--;
}
if(n%2 == 1){
nums[startx][starty] = count;
}
return nums;
}
}
其中loop表示在矩阵中完成一圈顺时针运动的次数,那么为什么总共循环次数为n/2,这是因为一圈顺时针运动会占两列和两行数据,因此要想给整个矩阵赋值只需要n/2次的操作。
另外值得注意的是,当n为奇数时,最后肯定会剩下单独的一个块需要被单独赋值,这是容易被忘记的。
今日收获:
学习到了滑动窗口思想和模拟行为的思想。