一、209.长度最小的子数组
方法一:暴力解法
两个循环,一个数组初始位置,一个结尾位置,寻找满足条件的情况
力扣中暴力解法超时
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int min =n+1;//最短数组长度
int sum = 0;
for(int i = 0; i<n ;i++){
sum = 0;
for(int j=i; j<n; j++){
sum += nums[j];
if(sum>=target & j-i+1<min){
min=j-i+1;
break;//找到最短退出
}
}
}
return min == n+1? 0:min;
}
}
方法二:滑动窗口
类似于双指针?因为最终考虑的是子数组的和,可以从0位置开始向右累加,直到满足大于target,记录下长度,减掉最左侧的数,若满足条件记录长度,并继续减左侧数,直到不满足条件则向右加,重复该过程,直到右侧指针到终点。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum =0;//子数组的和
int left=0;
int k = nums.length+1;
for(int i=0;i<nums.length;i++){
sum += nums[i];
while(sum>=target){
if(i-left+1<k){
k = i-left+1;
}
sum -= nums[left++];
}
}
//忘记判断
if(k==nums.length+1){
return 0;
}else{
return k;
}
}
}
//答案
class Solution {
// 滑动窗口
public int minSubArrayLen(int s, 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 >= s) {
result = Math.min(result, right - left + 1);//精简语法
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;//精简语法
}
}
错误记录:最后忘记判断没有结果的情况,应判断结果长度是否为初始值。
二、59.螺旋矩阵II
过程:本题拿到手没有思路,直接观看视频。自己直接上手不知道设什么为变量,也不知道如何写循环条件,也分不清要用for还是while。
看完讲解后感想:将整体过程分为重复的部分时(本题中为循环一圈)可以使用while循环,主要考虑循环终止条件。具体对数据进行遍历操作时,要使用for循环,并且要清楚起止条件,并考虑边界条件。
实现起来麻烦但不复杂,需要认真思考每一步的条件取值。要熟悉二维数组的索引。
class Solution {
public int[][] generateMatrix(int n) {
int loop=n/2;//循环的圈数
int startx=0;
int starty=0;
int count=1;
int[][] matrix =new int[n][n];
int num =1;//循环的数字
while(loop--!=0){
for(int j=starty;j<n-count;j++){
matrix[startx][j]=num++;
}
for(int i=startx;i<n-count;i++){
matrix[i][n-count]=num++;
}
for(int j=n-count;j>starty;j--){
matrix[n-count][j]=num++;
}
for(int i=n-count;i>startx;i--){
matrix[i][starty]=num++;
}
startx++;starty++;count++;
}
if(n%2==1){
matrix[startx][starty]=num;
}
return matrix;
}
}
错误点:循环执行完后已经将startx和starty加一,最后判断奇数中不需要再加。会溢出。
三、58. 区间和
文章讲解: 58. 区间和 | 代码随想录
前缀和思想计算区间和:在vec数组上 下标 2 到下标 5 之间的累加和,可以用 p[5] - p[1]

接触ACM模式:
import java.util.Scanner;
public class Main{
public static void main (String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();//获取数组长度
int[] vec = new int[n];//获取输入数组
int[] p = new int[n];//数组前缀和
int presum = 0;
for(int i=0;i<n;i++){
vec[i]=scanner.nextInt();
presum +=vec[i];
p[i]=presum;
}
while (scanner.hasNextInt()) {
int a = scanner.nextInt();
int b = scanner.nextInt();
int sum;
if (a == 0) {
sum = p[b];
} else {
sum = p[b] - p[a - 1];
}
System.out.println(sum);
}
scanner.close();
}
}
四、44. 开发商购买土地
同样运用前缀和的思路,和答案统计前缀和的位置不一样,结果一致。
import java.util.Scanner;
public class Main{
public static void main (String[] args) {
Scanner in=new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] matrix = new int[n][m];
int sum =0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
matrix[i][j]=in.nextInt();
sum += matrix[i][j];
}
}
//横向前缀和
int sumx=0;
int[] sumn =new int[n];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
sumx +=matrix[i][j];
}
sumn[i]=sumx;
}
//纵向前缀和
int sumy=0;
int[] summ =new int[m];
for(int j=0;j<m;j++){
for(int i=0;i<n;i++){
sumy +=matrix[i][j];
}
summ[j]=sumy;
}
int result = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
result = Math.min(result, Math.abs(sum -2* sumn[i]));
}
for(int j = 0; j < m; j++){
result = Math.min(result, Math.abs(sum -2* summ[j]));
}
System.out.println(result);
in.close();
}
}
五、今日总结
- 了解了前缀和思想来实现数组区间求和。
- 了解ACM模式,刚开始还是不太习惯,希望多应用后更加熟练。
六、数组总结
- 二分法:必须是有序数组,注意循环不变量。
- 双指针法:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
- 滑动窗口:滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。
- 模拟行为:真正解决题目的代码都是简洁的,或者有原则性的。
- 前缀和:求区间和。
769



被折叠的 条评论
为什么被折叠?



