代码随想录算法训练营第二天 | 209. 长度最小的子数组 59. 螺旋矩阵Ⅱ 区间和 开发商购买土地

209. 长度最小的子数组

第一次提交:没有考虑到right==nums.length的情况。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0, right = 1; // 左闭右开的窗口
        int res = Integer.MAX_VALUE;
        int sum = 0;
        // 如果数组长度为0
        if (0 == nums.length){
            return 0;
        }else{
            sum = nums[0]; // 赋初始值
        }
        while(right<=nums.length){
            if(sum>=target){
                res = res > right-left ? right-left : res;
                sum -= nums[left];
                left++;
            }else{
                sum += nums[right]; // Error: 
                right++;
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }
}

第二次提交:只是在第一次提交的基础上修改了一下,运行成功。但还是很别扭,在纠结什么时候赋值、什么时候循环。需要进一步再研究研究,整理出合适思路。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0, right = 1; // 左闭右开的窗口
        int res = Integer.MAX_VALUE;
        int sum = 0;
        // 如果数组长度为0
        if (0 == nums.length){
            return 0;
        }else{
            sum = nums[0]; // 赋初始值
        }
        while(right<=nums.length){
            if(sum>=target){
                res = res > right-left ? right-left : res;
                sum -= nums[left];
                left++;
            }else if (right==nums.length){
                break;
            }else{
                sum += nums[right];
                right++;
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }
}

代码随想录的解法如下:

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;
    }
}

本题滑动窗口总结


滑动窗口的区间:左闭右闭

  • 保证数组不会越界
  • 可以赋初始值

滑动窗口的循环:

  • for循环:右指针遍历
    • while循环:找到合适的左指针

总结:固定终止位置,寻找此时的起始位置

什么时候用for循环,什么时候用while循环?目前还是有点不懂


Math在lang包下,可以使用。

59. 螺旋矩阵Ⅱ

一开始想着每次赋值就是一次循环,那么循环要进行2*n-1次。但是这样前后循环没有关联,写不下去了……

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int offset = 0;
        int count = 2*n - 1;
        for(int i=n; i>0; i--){
            for(int cur = )
        }
    }
}

然后又看了一遍代码随想录:只能是循环按圈数来,每个循环进行四组赋值。(可以联想到,一年分四季,同比环比的意义完全不一样)

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int offset = 0; // offset的含义:赋值起始的offset,赋值终止的offset
        
        int loop = 0;
        int i,k;
        int num = 1;
        while(loop<n/2){
            for(i = offset; i<n-offset-1; i++){ // 左闭右开 // n-offset-1的含义
                res[offset][i] = num++;
            }
            for(i = offset; i<n-offset-1; i++){
                res[i][n-offset-1] = num++;
            }
            for(i = n-offset-1; i>offset; i--){
                res[n-offset-1][i] = num++;
            }
            for(i = n-offset-1; i>offset; i--){
                res[i][offset] = num++;
            }
            // 不要忘了
            loop++;
            offset++;
        }

        // 考虑到奇数
        if(1==n%2){
            res[n/2][n/2] = num; // 数组下标从0开始,不要忘了
        }

        return res;
    }
}

总结

再看代码随想录,还是有很多想法:

  1. 在循环时,每次 i 的范围都要在offsetn-offset-1之间。可以将其固定。
  2. offsetloop虽然值一样,但分成两个变量,有不同的含义。
  3. offsetloop,是否初始值设为-1更好一点?(

区间和

关键:前缀和
这道题很容易时间超限……

import java.util.Scanner;
class Main{
   public static void main(String[] args){
       Scanner s = new Scanner(System.in);
       int n = s.nextInt();
       
       int[] sum = new int[n];
       sum[0] = s.nextInt();
       for(int i=1; i<n; i++){
           sum[i] = s.nextInt() + sum[i - 1];
       }

       int start, end;
       while(s.hasNext()){
           start = s.nextInt();
           end = s.nextInt();
           System.out.println(sum[end] - (start==0 ? 0: sum[start-1]));
       }
       s.close();
   }
}

总结

  1. 不是lang包就要手动导入:import java.util.Scanner;
  2. scanner用完记得关闭……

开发商购买土地

以前做过的代码,先保存一下:

import java.util.Scanner;

public class Main{
   public static void main(String[] args){
       Scanner sc = new Scanner(System.in);
       int n = sc.nextInt();
       int m = sc.nextInt();
       int[][] blocks = new int[n][m];
       
       int[] sumLineN = new int[n];
       int[] sumColumnM = new int[m];
       
       int result = Integer.MAX_VALUE;
       
       // 读取数据,并且写出每行的前缀和
       for(int i=0; i<n; i++){
           for(int j=0; j<m; j++){
               blocks[i][j] = sc.nextInt();
               // 每行的和
               sumLineN[i] += blocks[i][j];
               // 每列的和 
               sumColumnM[j] += blocks[i][j];
           }
           // 将每行的和,变为前缀和
           if(i<n-1) sumLineN[i+1] = sumLineN[i];
       }
       // 土地价值总和
       int sum = sumLineN[n-1];
       float mid = (float)sum / 2;
       
       // 将每列的和,变为前缀和,并遍历
       for(int j=0; j<m; j++){
           if(j!=0) sumColumnM[j] += sumColumnM[j-1];
           
           result = Math.min(result, Math.abs(sum - sumColumnM[j] * 2));
       }
       
       if(result==0) {
           System.out.println(result);
           return;
       }
       
       
       // 遍历行的前缀和
       for(int i=0; i<n; i++){
           result = Math.min(result, Math.abs(sum - sumLineN[i] * 2));
       }
       
       
       System.out.println(result);
       return;
   }
}

以下是重写的:

import java.util.Scanner;
class Main{
    public static void main(String[] args){
        Scanner s = new Scanner(System.in);
        int n = s.nextInt();
        int m = s.nextInt();
        int[][] matrix = new int[n][m];
        int[] line = new int[n]; // 每行都有前缀和

        int[] column = new int[m]; // 每列都有前缀和
        for(int i=0; i<n; i++){
            for(int k=0; k<m; k++){
                matrix[i][k] = s.nextInt();
                line[i] += matrix[i][k]; // 顺便求出每行的和
                column[k] += matrix[i][k];
            }
            line[i] = line[i] + (i==0?0:line[i-1]); // 已经是前缀和了
        }
        for(int k=0; k<m; k++){
            column[k] = column[k] + (k==0?0:column[k-1]);
        }

        int res = Integer.MAX_VALUE;
        for(int i=0; i<n; i++){
            res = Math.min(res, Math.abs(line[n-1] - 2*line[i]));
        }
        for(int k=0; k<m; k++){
            res = Math.min(res, Math.abs(column[m-1] - 2*column[k]));
        }
        System.out.println(res);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值