迟到的Day2

day2

lc209 长度最小的子数组

> 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。 > > 示例: > > + 输入:s = 7, nums = [2,3,1,2,4,3] > + 输出:2 > + 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 >

暴力解法:

两个for循环, 不断地找符合条件的子数组,但是时间复杂度是O(n^2) 但是在最后leetcode跟新了数据 这种很明显超时了.

滑动窗口(双指针):

滑动窗口就是不断的调整子序列的起点和终点 直到得出想要的结果

俩指针

i 起点 j 终点 起点和终点最开始都在数组的第一个元素位置

先固定i 移动j 直到找到满足sum 满足了 就停止j终点

此时移动i起点 找到最短满足的 如果出现小于目标值的情况 那么固定i j继续移动

public int minSubArrayLen(int s, int[] nums){

    int l = 0, sum = 0, res = Integer.MAX_VALUE;

    for(int r = 0; r < nums.length; r++){
        sum += nums[r];
        while(sum >= s){
            res = Math.min(res, r - l + 1);
            sum -= nums[l++];
        }
    }
    return res == Integer.MAX_VALUE ? 0 : res;
}

lc59螺旋矩阵I

> 给你一个正整数 ` n` ,生成一个包含 ` 1` 到 ` n 2` 所有元素,且元素按顺时针顺序螺旋排列的 ` n x n` 正方形矩阵 ` matrix` 。 >

本题关键在于边界条件的处理 也就是四方形的四个角怎么处理


遵循一个不变量 到底是[ ] 还是[ )

如果[ ) 也就是在便利一条边时候 只要边的起点 不要边的终点 作为下一条的起点

题目输入n n就是 代表矩阵的大小 比如n = 4 那就返回4*4的矩阵

那么螺旋转圈次数就是n / 2次

如果n是奇数 除以2 除不尽剩余一个

因为每一圈的 起点都不算固定的 所以for循环的i 不可能是固定


 public static int[][] generateMatrix(int n) {
        int[][] arr = new int[n][n];
        int startX = 0, startY = 0, offset = 1,loop = 1,count = 1,x,y;
        while (loop <= n / 2){
            for(y = startY; y < n - offset; y++) arr[startX][y] = count++;
            for(x = startX; x < n - offset; x++) arr[x][y] = count++;
            for( ; y > startY; y--) arr[x][y] = count++;
            for( ; x > startX; x--) arr[x][y] = count++;
            startX++;
            startY++;
            loop++;
            offset++;
        }
        if(n % 2 == 1) arr[startX][startY] = count;
        return arr;
    }

前缀和

> 题目描述 > > 给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。 > > 输入描述 > > ** 第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。** > > 输出描述 > > 输出每个指定区间内元素的总和。 >

思路:

  1. 暴力解法

有一个区间之后 直接暴力把这个区间的和都累加一遍 但是提交代码提示超时

  1. 前缀和

前缀和就是利用计算过的子数组的和 从而降低区间查询需要累加计算的次数

在设计计算区间和时候非常有用

比如要计算vec[i] 在这个数组上的区间和

首先累加 p[i]表示下标0~i的vec累加和

计算下标2到5的区间和

区间下标 [2, 5] 的区间和,那么应该是 p[5] - p[1],而不是 p[5] - p[2]。

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] vec = new int[n]; //原本数组
        int[] p = new int[n];  //原本数组的区间和
        // 计算原本数组的区间和
        int preSum = 0;
        for(int i = 0; i < n; i++){
            vec[i] = sc.nextInt();
            preSum += vec[i];
            p[i] = preSum;
        }
        
        while (sc.hasNextInt()){
            int a = sc.nextInt();
            int b = sc.nextInt();
            int sum = 0;
            if(a == 0) sum = p[b];
            else sum = p[b] - p[a - 1];
            System.out.println(sum);
        }

    }
}

开发商买土地

> 【题目描述】 > > 在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。 > > 现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。 > > 然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 > > 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。 > > 注意:区块不可再分。 >

解法思路:

本题 要求任意两行或者两列之间的数值之和, 也就是前缀和

先计算出行 列方向的和 然后统计好前n行的和 q[n] 如果要求a行到b行之间的总和 那么就是q[b] - q[a - 1]

将一个二维数组划分为两部分,使得这两部分的和之差最小。

首先计算整个数组的总和 sum,然后分别求出每一行和每一列的和,存储在 rowSumcolSum 数组中。

接着,通过累加 rowSum 数组中的行和,逐步模拟横向划分,将前几行作为一部分、剩余行作为另一部分。每次划分时,计算当前划分后两部分和的差值,并更新最小差值 result。同理,对于纵向划分,累加 colSum 数组中的列和,模拟不同的列划分方式,计算两部分的差值,并更新最小差值。最终输出的 result 就是所有可能划分方式中两部分和的最小差值。

import java.util.*;

public class Main{
    
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int sum = 0;
        int[][] vec = new int[n][m];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                vec[i][j] = sc.nextInt();
                sum += vec[i][j];
            }
        }
        
        // 统计每行的和
        int[] rowSum = new int[n];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                rowSum[i] += vec[i][j];
            }
        }
        
        // 统计每列的和
        int[] colSum = new int[m];
        for(int j = 0; j < m; j++){
            for(int i = 0; i < n; i++){
                colSum[j] += vec[i][j];
            }
        }
        
        int res = Integer.MAX_VALUE;
        
        // 计算行划分的最小差值
        int rowCut = 0;
        for(int i = 0; i < n; i++){
            rowCut += rowSum[i];
            res = Math.min(res, Math.abs(sum - 2 * rowCut));
        }
        
        // 计算列划分的最小差值
        int colCut = 0;
        for(int j = 0; j < m; j++){
            colCut += colSum[j];
            res = Math.min(res, Math.abs(sum - 2 * colCut));
        }
        
        System.out.println(res);
        
        sc.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值