代码随想录Day02|LeetCode209.长度最小的子数组、LeetCode59.螺旋矩阵、KamaCoder58.区间和、KamaCoder44.开发商购买土地


代码随想录开源LeetCode题单:代码随想录


题目

1.LeetCode209

LeetCode209.长度最小的子数组

1.1 滑动窗口

1.1.1 思路

滑动窗口定义了起始位置终止位置两个索引来将元素框在其中,在改变终止位置的同时让起始位置做出对应的改变,实现窗口的滑动,从而得到符合要求的结果。

题目要求寻找元素和大于等于target的最小子数组,可以使用滑动窗口。

定义一个f循环体,终止位置从0开始后移直至数组中最后一个元素,在循环体中,

  1. 终止位置right每后移一位就向当前和sum中加入nums[right]
  2. 一旦当前和sum大于等于target,就记录当前的滑动窗口长度subL,即right-left+1。更新返回结果resultsubLresult中的较小值。
  3. 当前和sum减去起始位置元素,起始位置left后移一位,即实现滑动窗口的滑动。
    循环结束后,检查返回结果result是否改变,若未改变则说明没有找到最小子数组。

时间复杂度:O(n)

1.1.2 代码
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0,   // 滑动窗口起始位置
            right = 0,  // 滑动窗口终止位置
            sum = 0,    // 滑动窗口内元素和
            subL = 0,   // 满足`sum >= target`的最小子数组长度
            result = Integer.MAX_VALUE;     // 返回值,同时最大整数用于标记该值是否发生改变
        
        for(left = 0, right = 0; right < nums.length; right++){
            // 求滑动窗口内元素的和
            sum += nums[right];
            while(sum >= target){
                subL = right -left + 1; // 当前满足要求的滑动窗口长度
                result = subL < result ? subL : result; // 记录最小长度
                sum -=  nums[left++];
            }
        }
        // 若result值未更新,则不存在符合条件的子数组,返回0
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

1.2 前缀和+二分查找

解法来源:LeetCode精选题解 4

1.2.1 思路

申请临时数组 sumssums[i] 表示nums i 个元素的和,
题中说nums元素为正整数,则相加的和越来越大,即是sums数组中的元素是递增的。
只需要找到 sums[k]-sums[j]>=s,则 k-j 就是满足的连续子数组,但不一定是最小的,所以要继续找,直到找到最小的为止。
为避免双重for循环暴力求解,可以把求sums[k]-sums[j]>=s 变为求 sums[j]+s<=sums[k],因为sums中元素递增的,故只需要求sum[j]+s 的值,然后使用二分法查找即可找到这个 k

时间复杂度O(nlogn)

1.2.2 代码
public int minSubArrayLen(int s, int[] nums) {
        int length = nums.length;
        int min = Integer.MAX_VALUE;
        int[] sums = new int[length + 1];
        for (int i = 1; i <= length; i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        for (int i = 0; i <= length; i++) {
            int target = s + sums[i];
            int index = Arrays.binarySearch(sums, target);
            if (index < 0)
                index = ~index;
            if (index <= length) {
                min = Math.min(min, index - i);
            }
        }
        return min == Integer.MAX_VALUE ? 0 : min;
    }

2.LeetCode59

LeetCode59.螺旋矩阵

2.1 思路

本题要求从外圈到内圈顺时针填充矩阵,模拟图如下。

螺旋矩阵
每一圈都应按照

  1. 左–>右、上–>下、右–>左、下–>上 的顺序来填充。
    遵循循环不变量原则,每一段都取左闭右开区间。

2.2 代码

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        int cnt = 0,	// 圈数索引
        	num = 1;	// 待填充数值
        //无论奇数圈还是偶数圈,索引都不超过(n + 1) / 2
        while(cnt < (n + 1) / 2){	
            int i = 0 + cnt, 
            	j =  0 + cnt;
            while(j < n - cnt){ //左-->右
                result[i][j++] = num++; 
            }
            j--;    num--;
            while(i < n - cnt){ //上-->下
                result[i++][j] = num++; 
            }
            i--;    num--;
            while(j >= 0 + cnt){ //右-->左
                result[i][j--] = num++;
            }
            j++;    num--;
            while(i > 0 + cnt){ //下-->上
                result[i--][j] = num++;
            }
            i++;    //num--;
            cnt++;
        }
        return result;
    }
}

3.KamaCoder58

KamaCoder58.区间和

3.1 思路

代码随想录 文章讲解

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

4.KamaCoder44

KamaCoder44.开发商购买土地

4.1 思路

前缀和
代码随想录 文章讲解

4.2 代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.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] = scanner.nextInt();
                sum += vec[i][j];
            }
        }

        // 统计横向
        int[] horizontal = new int[n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                horizontal[i] += vec[i][j];
            }
        }

        // 统计纵向
        int[] vertical = new int[m];
        for (int j = 0; j < m; j++) {
            for (int i = 0; i < n; i++) {
                vertical[j] += vec[i][j];
            }
        }

        int result = Integer.MAX_VALUE;
        int horizontalCut = 0;
        for (int i = 0; i < n; i++) {
            horizontalCut += horizontal[i];
            result = Math.min(result, Math.abs(sum - 2 * horizontalCut));
        }

        int verticalCut = 0;
        for (int j = 0; j < m; j++) {
            verticalCut += vertical[j];
            result = Math.min(result, Math.abs(sum - 2 * verticalCut));
        }

        System.out.println(result);
        scanner.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值