【LeetCode】Sama的个人记录_60

在这里插入图片描述

差分法。
差分法就是不记录当前具体的值,而是记录值的变化量。出生/死亡人数、上/下公交车,都是这类题目。
class Solution {
    public int maximumPopulation(int[][] logs) {
    	// 差分法:arr记录人口变化量
        int[] arr = new int[101];
        for (int[] log : logs) {
            arr[log[0] - 1950]++;
            arr[log[1] - 1950]--;
        }
        int max = 0;
        int num = 0;
        int res = 0;
        for (int i = 0; i < 101; i++) {
            num += arr[i];
            if (num > max) {
                max = num;
                res = i + 1950;
            }
        }
        return res;
    }
}

 
 

在这里插入图片描述

滑动窗口,以及贪吃蛇优化

```java
class Solution_1855 {
    public int maxDistance(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int L = 0;
        int R = 0;
        while (L < len1 && R < len2) {
            if (nums1[L] > nums2[R]) {
                L++;
            }
            R++;
        }
        // 因为本题中的窗口大小可以是0(一般的滑窗大小至少也是1的),所以特判一下
        return R - L - 1 >= 0 ? R - L - 1 : 0;
    }
}

 
 

在这里插入图片描述

2 * (3 + 2 + 5)这个式子中,有两个可变量,"子数组最小值""子数组的和",按照一般的思路只能是暴力子数组的范围(i, j)。
我们不妨先固定一个变量::最小值。
在遍历的时候,遍历到数字作为最小值固定,那么它所在的子数组显然越大越好(和就越大);我们通过使用两次单调栈,就能找出子数组的左右边界。
class Solution {
    public int maxSumMinProduct(int[] nums) {
        int len = nums.length;

        // 求前缀和
        long[] preSum = new long[len + 1];
        for (int i = 0; i < len; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }

        // 左右边界
        int[] leftBound = new int[len];
        int[] rightBound = new int[len];
        Arrays.fill(leftBound, 0);
        Arrays.fill(rightBound, len - 1);

        // 两次单调栈,找出右、左边界(右、左侧第一个小于它的数的位置)
        ArrayDeque<Integer> stack1 = new ArrayDeque<>();
        for (int i = 0; i < len; i++) {
            while (!stack1.isEmpty() && nums[i] < nums[stack1.peek()]) {
                rightBound[stack1.pop()] = i - 1;
            }
            stack1.push(i);
        }
        ArrayDeque<Integer> stack2 = new ArrayDeque<>();
        for (int i = len - 1; i >= 0; i--) {
            while (!stack2.isEmpty() && nums[i] < nums[stack2.peek()]) {
                leftBound[stack2.pop()] = i + 1;
            }
            stack2.push(i);
        }

        // 遍历到的数字固定为最小值
        long res = 0L;
        for (int i = 0; i < len; i++) {
            int L = leftBound[i];
            int R = rightBound[i];
            res = Math.max(res, (preSum[R + 1] - preSum[L]) * nums[i]);
        }
        return (int) (res % (1000000007));
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 

检索标记:
5750. 人口最多的年份给你一个二维整数数组 logs ,其中每个 logs[i] = [birthi, deathi] 表示第 i 个人的出生和死亡年份。年份 x 的 人口 定义为这一年期间活着的人的数目。第 i 个人被计入年份 x 的人口需要满足:x 在闭区间 [birthi, deathi - 1] 内。注意,人不应当计入他们死亡当年的人口中。返回 人口最多 且 最早 的年份。1855. 下标对中的最大距离给你两个 非递增 的整数数组 nums1​​​​​​ 和 nums2​​​​​​ ,数组下标均 从 0 开始 计数。下标对 (i, j) 中 0 <= i < nums1.length 且 0 <= j < nums2.length 。如果该下标对同时满足 i <= j 且 nums1[i] <= nums2[j] ,则称之为 有效 下标对,该下标对的 距离 为 j - i​​ 。​​返回所有 有效 下标对 (i, j) 中的 最大距离 。如果不存在有效下标对,返回 0 。一个数组 arr ,如果每个 1 <= i < arr.length 均有 arr[i-1] >= arr[i] 成立,那么该数组是一个 非递增 数组。1856. 子数组最小乘积的最大值一个数组的 最小乘积 定义为这个数组中 最小值 乘以 数组的 和 。比方说,数组 [3,2,5] (最小值是 2)的最小乘积为 2 * (3+2+5) = 2 * 10 = 20 。
给你一个正整数数组 nums ,请你返回 nums 任意 非空子数组 的最小乘积 的 最大值 。由于答案可能很大,请你返回答案对 109 + 7 取余 的结果。请注意,最小乘积的最大值考虑的是取余操作 之前 的结果。题目保证最小乘积的最大值在 不取余 的情况下可以用 64 位有符号整数 保存。子数组 定义为一个数组的 连续 部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值