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

209.长度最小的子数组

Leetcode链接: link

class Solution {
    public static int minSubArrayLen(int target, int[] nums) {
        int front = 0;
        int end = 0;
        int sum = 0;
        int result = 0;
        while(end < nums.length){
            sum += nums[end];
            while(sum >= target){
                if(result == 0){
                    result = end-front+1;
                }else{
                    result = Math.min(result, end-front+1);
                }
                sum -= nums[front];
                front ++;
            }
            end++;

        }
        return result;
    }
}

这一题我写了很久,一开始就知道需要使用滑动窗口来解决,但是我一开始并没有使用两个loop。导致我写的异常的艰难。而且还在一开始没看清题目,以为只能写“子数组总和等于 target 的长度最小的子数组”。后面写出来发现怎么也过不了,就选择了看答案。看到使用两个loop之后茅塞顿开。下面是我第一次的代码,我觉得写起来也挺有意义的,虽然花费了很长的时间才理清楚指针的移动逻辑。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        if (n == 0) {
            return 0;
        }

        int front = 0;
        int end = 0;
        int sum = 0;
        int result = 0;
        while(front < n){
            if(sum < target){
                if(end >= n){
                    break;
                }
                sum += nums[end];
                end ++;
            }else if(sum > target){
                sum -= nums[front];
                front++;
            }else{
                if(result == 0){
                    result = end-front;
                }else{
                    result = Math.min(result, end-front);
                }
                sum -= nums[front];
                front++;
            }
        }
        return result;
    }
}

59.螺旋矩阵II

Leetcode链接: link

class Solution {
    public int[][] generateMatrix(int n) {
        int x = 0;
        int y = 0;
        int [][] matrix = new int[n][n];
        int count = 1;
        for(int i = 0; i < n/2; i++){
            for(; y < n-i-1; y++){
                matrix[x][y] = count;
                count++; 
            }
            for(; x < n-i-1; x++){
                matrix[x][y] = count;
                count++; 
            }
            for(; y > i; y--){
                matrix[x][y] = count;
                count++; 
            }
            for(; x > i; x--){
                matrix[x][y] = count;
                count++; 
            }
            x++;
            y++;
        }
        if(n%2 == 1){
            matrix[x][y] = count;
        }
        return matrix;
    }
}

这题一拿到手上就知道该怎么做了,定义一个matrix,然后在旋转修改里面的值。一开始写的很正常,写的是最外面的循环。但是后面就出问题了。我一开始的for循环是这样的:

for(; y < n-1; y++)
for(; x < n-1; x++)
for(; y > 0; y--)
for(; x > 0; x--)

这只是对最外面进行了循环并没有对里面进行循环。我也是debug了很久才知道该怎么做。把i加入进去。修改之后变成了这样:

for(; y < n-i; y++)
for(; x < n-i; x++)
for(; y > i; y--)
for(; x > i; x--)

现在看来真是脑子瓦特了。debug修改这个loop就花了我将近半小时。不得不说写代码是真的花费时间的事情。

59.前缀和算法

链接: link

这种方法应该是算区间和最快的方法了。这题也很巧妙的在读取用户输入的时候就可以生成我们的“前缀和array”。如果不是这种读取模式的话,我觉得应该是还是直接用for循环把直接取出里面数组加在一起会更快。

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

59.开发商购买土地

#include <iostream>
#include <vector>
#include <climits>

using namespace std;
int main () {
    int n, m;
    cin >> n >> m;
    int sum = 0;
    vector<vector<int>> vec(n, vector<int>(m, 0)) ;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> vec[i][j];
            sum += vec[i][j];
        }
    }
    // 统计横向
    vector<int> horizontal(n, 0);
    for (int i = 0; i < n; i++) {
        for (int j = 0 ; j < m; j++) {
            horizontal[i] += vec[i][j];
        }
    }
    // 统计纵向
    vector<int> vertical(m , 0);
    for (int j = 0; j < m; j++) {
        for (int i = 0 ; i < n; i++) {
            vertical[j] += vec[i][j];
        }
    }
    int result = INT_MAX;
    int horizontalCut = 0;
    for (int i = 0 ; i < n; i++) {
        horizontalCut += horizontal[i];
        result = min(result, abs(sum - horizontalCut - horizontalCut));
    }
    int verticalCut = 0;
    for (int j = 0; j < m; j++) {
        verticalCut += vertical[j];
        result = min(result, abs(sum - verticalCut - verticalCut));
    }
    cout << result << endl;
}

这题是把上面那一题的前缀和算法演变成了2D数组的前缀和求法。先在读取用户输入的时候顺便把2D数组里所有的数字加起来找到sum。然后再循环分别求出每一行的sum和每一列的sum,分别放入两个array。最后对这两个array进行遍历。

难点:

horizontalCut += horizontal[i];
result = min(result, abs(sum - horizontalCut - horizontalCut));

这两个代码,我思考了很久才看明白。本质上abs(sum - horizontalCut - horizontalCut)就是等于切割了2D array并且算出了左右两边的差值。

下面就是我自己为了方面记忆写的一个例子。
我们先是得出sum = 51,我们从6开始,sum - horizontalCut - horizontalCut就等于后面全部element的加起来减去6。下一个15,我们的cut就要变成15+6 = 21.
例子

今日收获

复习了滑动窗口。学习了前缀和(也可能之前学过忘了)好像有点印象。虽然滑动窗口花费了自己大量的时间,但是以后应该写起来不会那么困难。还有前缀和的多种用法。感觉真的很难,就算是知道了可能也不太会应用。

记录一下自己的学习时长:

leetcode:3h
博客:0.5h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值