算法day02 | lc.209.长度最小的子数组 | lc.59.螺旋矩阵II | 区间和 |开发商购买土地

209.长度最小的子数组

力扣题目链接

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

  • 输入:s = 7, nums = [2,3,1,2,4,3]
  • 输出:2
  • 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

提示:

  • 1 <= target <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

思路:

滑动窗口:2个指针,头指针用于遍历,尾指针不动,当满足条件的结果出现后,尾指针逐步移动,再进行判断,如此往复直至结束。

代码:

public int minSubArrayLen(int target, int[] nums) {
        int len = nums.length;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        int first =0;
        for(int end=0; end < len; end++){
            sum+=nums[end];
            while(sum>=target){
                //找到满足条件的子数组,记录数组长度
                result = Math.min(result, end - first + 1);
                //重点是这个代码,指针向右移动,总和也要相应变化,向后移动
                sum -= nums[first++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }

59.螺旋矩阵II

力扣题目链接(opens new window)

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

示例:

输入: 3

输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

思路:

类似二分法思想,重点是确定区间边界,左闭右闭还是左闭右开,本题采用左闭右开

代码:

public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        //每圈的起始坐标,实际上startX和startY只需要用一个即可,因为二者始终相等,用2个方便理解
        int startX = 0;
        int startY = 0;
        int count = 1;
        //行
        int i ;
        //列
        int j ;

        //循环的圈数,结束循环的条件以及缩圈用,每缩一圈,循环次数少1
        int loop = 1;
        //采取左闭右开方式
        while(loop <= n/2){
            //上
            for(j = startY; j< n-loop; j++){
                result[startX][j] = count++;
            }
            //右
            for(i = startX; i< n-loop; i++){
                result[i][j] = count++;
            }
            //下
            for(; j> startY; j--){
                result[i][j] = count++;
            }
             //左
            for(; i> startX; i--){
                result[i][j] = count++;
            }
            startX++;
            startY++;
            loop++;

        }
        if(n%2!=0){
            result[startX][startY] = count;
        }
        return result;

    }

区间和

题目描述

给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。

输入描述:

第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。

输出描述:

输出每个指定区间内元素的总和。

输入示例

5
1
2
3
4
5
0 1
1 3

输出示例

3
9

数据范围:

0 < n <= 100000

思路:

在涉及计算区间问题时,采用前缀和的方式,前缀和思想是重复利用计算过的子数组之和,减少重复计算。

代码:

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int len = scanner.nextInt();
        int[] nums = new int[len];
        int[] preSum = new int[len];
        int sum = 0;
        for (int i=0;i<len ; i++){
            nums[i] = scanner.nextInt();
            sum += nums[i];
            preSum[i] = sum;
        }

        while(scanner.hasNextInt()){
            int first = scanner.nextInt();
            int end = scanner.nextInt();
            int result;
            if(first == 0){
                result = preSum[end];
            }else{
                result = preSum[end] - preSum[first-1];
            }

            System.out.println(result);

        }
        scanner.close();
    
    }

开发商购买土地

题目描述:

在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。 

现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。

然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。 

注意:区块不可再分。

输入描述:

第一行输入两个正整数,代表 n 和 m。 

接下来的 n 行,每行输出 m 个正整数。

输出描述:

请输出一个整数,代表两个子区域内土地总价值之间的最小差距。

输入示例:

3 3
1 2 3
2 1 3
1 2 3

输出示例

0

提示信息

如果将区域按照如下方式划分:

1 2 | 3
2 1 | 3
1 2 | 3 

两个子区域内土地总价值之间的最小差距可以达到 0。

数据范围:

1 <= n, m <= 100;
n 和 m 不同时为 1。

思路:

难点在于理解题目意思,转换成比较区间和的问题,采用前缀和,或更优化的解,在每行或每列末尾进行一次判断,

代码:

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        //记录当前二维数组
        int[][] nums = new int[n][m];
        int result = Integer.MAX_VALUE;
        int sum = 0;
        for (int i=0; i<n; i++){
            for (int j=0; j<m; j++){
                nums[i][j] = sc.nextInt();
                sum += nums[i][j];
            } 
        } 
        
        //遍历行
		int counti =0;
        for (int i=0; i<n; i++){
            for (int j=0; j<m; j++){
                counti+= nums[i][j];
                if(j == m-1){
				//在行末进行判断,相当于以当前行为分隔线
                   result = Math.min(result, Math.abs(sum - 2*counti));
                }
            } 
        } 
        
        //遍历列
		int countj =0;
        for (int j=0; j<m; j++){
            for (int i=0; i<n; i++){
                countj += nums[i][j];
                if(i == n-1){
				//在列末进行判断,相当于以当前列为分隔线
                   result = Math.min(result, Math.abs(sum - 2*countj));
                }
            } 
        } 
        
        System.out.println(result);
        sc.close();
        
        
    }

结合昨天的文章,2天涉及到的指针,简单总结下:

1、移除元素:快慢指针:快指针用于遍历,慢指针用于保存符合要求的元素;
2、有序数组的平方:双指针:一个指向起始位置,一个指向终止位置,然后向中间移动;
3、长度最新的子数组:滑动窗口:也是2个指针,头指针用于遍历,尾指针不动,当满足条件的结果出现后,尾指针逐步移动,再进行判断,如此往复直至结束;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值