977.有序数组的平方
- 题目链接:977.有序数组的平方
- 解题思路:
- 暴力法:直接把每个数原地平方,然后排序整个数组,这种方法的时间复杂度是 O(n + nlogn)。
- 双指针法:因为数组是有序的,平方后最大的元素一定在数组两侧而不会在数组的中间位置,因此可以设定两个指针从数组的头尾开始进行比较,并按大小顺序放进一个新的数组里,同时完成平方和排序的工作,这种方法的时间复杂度是O(n)。
- 主要难点:双指针方法的运用。
- 解题步骤:
- 设定头尾两个指针以及一个空的新数组,长度与原数组相同
- 比较头尾指针对应元素平方的值,将大的数放进新数组的末尾,更新指针,如果的左边的大就左指针右移一位,如果右边大的话就右指针左移一位
- 重复上述过程,直到左右指针相同时完成循环,返回新的数组即为所求。
- 代码:
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length-1;
int[] result = new int[nums.length];
int k = nums.length-1;
while(l<=r) {
if(nums[l]*nums[l]>nums[r]*nums[r]){
result[k] = nums[l]*nums[l];
k--;
l++;
}else{
result[k] = nums[r]*nums[r];
k--;
r--;
}
}
return result;
}
}
209.长度最小的子数组
- 题目链接:209.长度最小的子数组
- 解题思路:
- 暴力法:循环找到每一个满足题目要求的子数组并保存长度,最后比较大小选最短的一个,时间复杂度O(n²)
- 滑动窗口法(和双指针差不多):设定一前一后两个指针,每当得到符合题目要求的数组时更新数组值,并向前移动滑动窗口。时间复杂度为O(n)。
- 主要难点:滑动窗口的前移过程
- 解题步骤:
- 设置左右指针初始为0,新建一个变量赋无穷大值,用来保存最终结果即最短的数组长度
- 右指针开始向前移动,每移动一位判断当前滑动窗口内的和是否大于等于target
- 若满足要求,则更新数组长度值,永远保存最小,同时数组和减去左指针对应的数,左指针右移一位。
- 若不满足要求则右指针继续向右移动
- 当右指针移到数组末尾,左指针完成所有移动后停止,输出最短数组长度变量值,若其仍为初始最大值则返回0.
- 代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for(int right = 0;right<nums.length;right++){
sum += nums[right];
while(sum>=target){
//更新当前长度,取最短
if(right - left + 1 < result){
result = right - left + 1;
}
sum -= nums[left];//把最前面的一位减掉
left++;//左指针右移一位
}
}
if(result == Integer.MAX_VALUE){
return 0;
}else{
return result;
}
}
}
59.螺旋矩阵Ⅱ
- 题目链接:59.螺旋矩阵Ⅱ
- 解题思路:本题基本不涉及什么算法,主要是按照顺序填充矩阵,对循环判断的条件逻辑要求较高。类似前一天做的二分法,这道题也需要时刻满足循环不变量原则,即在填充的过程中坚持左闭右开或左开右闭,从外向内循环填充整个矩阵。
- 主要难点:循环不变量原则的满足,每个部分填充的判断条件逻辑,以及n为奇数时手动填充中间位置的数值。
- 解题步骤:
- 新建矩阵,新建循环过程中需要用到的变量
- 使用左闭右开规则进行填充,分别写四个方向的填充循环代码
- 当n为奇数时,需要在最后手动填充矩阵最中央的数值
- 代码:
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int loop = 0;//循环次数
int start = 0;//每次循环开始点
int num = 1;//填充数字
int i,j;
//填充过程全部坚持左闭右开规则
while(loop++<n/2) {
//上侧左到右
for(j=start;j<n-loop;j++){
res[start][j]=num++;
}
//右侧上到下
for(i=start;i<n-loop;i++){
res[i][j]=num++;
}
//下侧右到左
for(;j>=loop;j--){
res[i][j]=num++;
}
//左侧下到上
for(;i>=loop;i--){
res[i][j]=num++;
}
start++;
}
//特别情况:当n为奇数时,需要手动填充矩阵最中央位置元素
if(n%2==1){
res[start][start]=num;
}
return res;
}
}
总结
今天的三道题之前都有做过一遍,再拿来做的时候有思路但是写的过程还是容易出各种错误,这三道题的主要思想是双指针法和循环不变量原则,双指针法使用两个指针进行移动能够将两个for循环减少到一个for循环,提高程序的时间复杂度;循环不变量原则是写代码时的一种原则,通过固定的规则去编码能够减少循环判断条件的复杂度,让逻辑更加清晰。