1. 今日收获:滑动窗口,模拟,前缀和
2. 滑动窗口,例题 209.长度最小的子数组
题目链接:209.长度最小的子数组
思想:定义起点和终点两个指针,终点指针不断前移使得窗口中的值大于等于target,起点指针在满足窗口中的值大于target的条件之后要前移缩小窗口,使得窗口长度尽可能小
方法:滑动窗口
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 滑动窗口
int len=nums.length;
int start=0;
int sum=0;
int minL=Integer.MAX_VALUE;
for (int end=0;end<len;end++){ // 终点遍历数组
sum+=nums[end];
while (sum>=target){ // 满足条件缩小窗口
int subL=end-start+1;
minL=minL>subL?subL:minL;
sum-=nums[start];
start++;
}
}
return minL==Integer.MAX_VALUE?0:minL;
}
}
总结:第一感觉是滑动窗口和快慢指针很像,但是不同之处在于快慢指针只需要元素满足一个条件就好,但是在本题中需要同时满足值大于等于target和窗口长度最小两个条件,起点和终点指针分别都有"任务在身"。
3. 模拟,例题 59. 螺旋矩阵Ⅱ
题目:59. 螺旋矩阵Ⅱ
思想:从外到内按圈圈"上右下左"赋值给二维数组。把握循环不变量原则,在处理边界条件时按“左闭右开”的原则,只处理第一个角元素和中间的元素。
方法:循环不变量
class Solution {
public int[][] generateMatrix(int n) {
int[][] result=new int[n][n];
int startX=0;
int startY=0;
int offset=1;
int count=1;
int circle=n/2;
// 每行或每列包括起始节点,不包括终止节点
while (circle!=0){ // 转的圈数
int i=startX;
int j=startY;
// 上面的行
for ( ;j<n-offset;j++){
result[i][j]=count;
count++;
}
// 右边的列
for (;i<n-offset;i++){
result[i][j]=count;
count++;
}
// 下面的行
for ( ;j>startY;j--){
result[i][j]=count;
count++;
}
// 左边的列
for ( ;i>startX;i--){
result[i][j]=count;
count++;
}
// 下一圈
startX++;
startY++;
offset++;
circle--;
}
if (n%2==1){
result[n/2][n/2]=n*n;
}
return result;
}
}
总结:做模拟题时要找到规律,特别是这道题中的offset变量不太好想。其实内圈和外圈的循环不同之处就在于行列都缩小了一圈;另外定义好行列遍历时的边界也很重要,选择“左闭右开”,那么所有行列的处理都可以按统一的规则来。(写代码时画3*3的矩阵,把边界的坐标点都写出来会辅助思考)
4. 区间和,例题 977.有序数组的平方
思想:提前计算好数组每个下标的前缀和,那么指定区间和就是特定下标的前缀和相减
方法:前缀和
import java.lang.*;
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int len = sc.nextInt();
int[] array= new int[len];
int[] p= new int[len];
for (int i=0;i<len;i++){
array[i]=sc.nextInt();
}
p[0]=array[0];
for (int i=1;i<len;i++){
p[i]=p[i-1]+array[i]; // 计算前缀和
}
while (sc.hasNextInt()){
int a=sc.nextInt();
int b=sc.nextInt();
if (a==0){
System.out.println(p[b]);
}else {
System.out.println(p[b]-p[a-1]);
}
}
}
}
总结:有些操作中的值需要重复计算,这时就可以把重复计算提前准备好,起到简化的作用