跳转至

力扣第240场周赛

题一 人口最多的年份

描述

给你一个二维整数数组 logs ,其中每个 logs[i] = [birthi, deathi] 表示第 i 个人的出生和死亡年份。

年份 x 的 人口 定义为这一年期间活着的人的数目。第 i 个人被计入年份 x 的人口需要满足:x 在闭区间 [birthi, deathi - 1] 内。注意,人不应当计入他们死亡当年的人口中。

返回 人口最多 且 最早 的年份。

示例 1:

输入:logs = [[1993,1999],[2000,2010]] 输出:1993 解释:人口最多为 1 ,而 1993 是人口为 1 的最早年份。 示例 2:

输入:logs = [[1950,1961],[1960,1971],[1970,1981]] 输出:1960 解释: 人口最多为 2 ,分别出现在 1960 和 1970 。 其中最早年份是 1960 。

提示:

1 <= logs.length <= 100 1950 <= birthi < deathi <= 2050

思路

用一个数组存储所有年份出生的人数减去去世的人数,然后遍历得到人口最多的年份。

代码

package JavaCode.contest.weekly.n201_300.n240;

public class N1 {
    public int maximumPopulation(int[][] logs) {
        int[] book=new int[101];
        for (int[] log:logs){
            book[log[0]-1950]++;
            book[log[1]-1950]--;
        }
        int s=0;
        int max=0;
        int res=1950;
        for (int i=0;i< book.length;i++){
            s+=book[i];
            if(max<s){
                max=s;
                res=i+1950;
            }
        }
        return res;
    }
}

题二 下标对中的最大距离

描述

给你两个 非递增 的整数数组 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] 成立,那么该数组是一个 非递增 数组。

示例 1:

输入:nums1 = [55,30,5,4,2], nums2 = [100,20,10,10,5] 输出:2 解释:有效下标对是 (0,0), (2,2), (2,3), (2,4), (3,3), (3,4) 和 (4,4) 。 最大距离是 2 ,对应下标对 (2,4) 。 示例 2:

输入:nums1 = [2,2,2], nums2 = [10,10,1] 输出:1 解释:有效下标对是 (0,0), (0,1) 和 (1,1) 。 最大距离是 1 ,对应下标对 (0,1) 。 示例 3:

输入:nums1 = [30,29,19,5], nums2 = [25,25,25,25,25] 输出:2 解释:有效下标对是 (2,2), (2,3), (2,4), (3,3) 和 (3,4) 。 最大距离是 2 ,对应下标对 (2,4) 。 示例 4:

输入:nums1 = [5,4], nums2 = [3,2] 输出:0 解释:不存在有效下标对,所以返回 0 。

提示:

1 <= nums1.length <= 10^5 1 <= nums2.length <= 10^5 1 <= nums1[i], nums2[j] <= 10^5 nums1 和 nums2 都是 非递增 数组

思路

二分查找。

代码

package JavaCode.contest.weekly.n201_300.n240;

public class N2 {
    public int maxDistance(int[] nums1, int[] nums2) {
        int res=0;
        for (int i=0;i<nums1.length;i++){
            if(i>=nums2.length)break;
            int j=find(nums2,i,nums1[i]);
            if(j!=-1){
                res=Math.max(j-i,res);
            }
        }
        return res;
    }

    private int find(int[] nums, int i, int tar) {
        if(nums[i]<tar)return -1;
        int l=i,r=nums.length-1;
        int res=i;
        while (l<=r){
            int mid=(l+r)/2;
            if(nums[mid]>=tar){
                res=Math.max(res,mid);
                l=mid+1;
            }
            else r=mid-1;
        }
        return res;
    }
}

题三 子数组最小乘积的最大值

描述

一个数组的 最小乘积 定义为这个数组中 最小值 乘以 数组的 和 。

比方说,数组 [3,2,5] (最小值是 2)的最小乘积为 2 * (3+2+5) = 2 * 10 = 20 。 给你一个正整数数组 nums ,请你返回 nums 任意 非空子数组 的最小乘积 的 最大值 。由于答案可能很大,请你返回答案对 109 + 7 取余 的结果。

请注意,最小乘积的最大值考虑的是取余操作 之前 的结果。题目保证最小乘积的最大值在 不取余 的情况下可以用 64 位有符号整数 保存。

子数组 定义为一个数组的 连续 部分。

示例 1:

输入:nums = [1,2,3,2] 输出:14 解释:最小乘积的最大值由子数组 [2,3,2] (最小值是 2)得到。 2 * (2+3+2) = 2 * 7 = 14 。 示例 2:

输入:nums = [2,3,3,1,2] 输出:18 解释:最小乘积的最大值由子数组 [3,3] (最小值是 3)得到。 3 * (3+3) = 3 * 6 = 18 。 示例 3:

输入:nums = [3,1,5,6,4,2] 输出:60 解释:最小乘积的最大值由子数组 [5,6,4] (最小值是 4)得到。 4 * (5+6+4) = 4 * 15 = 60 。

提示:

1 <= nums.length <= 10^5 1 <= nums[i] <= 10^7

思路

  • 预处理sum。

  • 依次遍历,假定当前值就是序列中的最小值,通过单调栈找到另一个边界计算即可。

代码

package JavaCode.contest.weekly.n201_300.n240;

import java.util.Stack;

public class N3 {
    public int maxSumMinProduct(int[] nums) {
        final int MOD= (int) (Math.pow(10,9)+7);
        long[] sum=new long[nums.length+1];
        for (int i=1;i<=nums.length;i++){
            sum[i]=sum[i-1]+nums[i-1];
        }
        long res=0;
        Stack<Integer> stack=new Stack<>();
        for (int i=0;i<nums.length;i++){
            while (!stack.isEmpty()&&nums[i]<=nums[stack.peek()]){
                int peek=stack.pop();
                int l=stack.isEmpty()?-1:stack.peek();
                res=Math.max(res, nums[peek] * (sum[i] - sum[l + 1]));
            }
            stack.push(i);
        }
        while (!stack.isEmpty()){
            int peek=stack.pop();
            int l=stack.isEmpty()?-1:stack.peek();
            res=Math.max(res, (sum[nums.length] - sum[l + 1]) *nums[peek]);
        }
        return (int) (res%MOD);
    }
}

题四 有向图中最大颜色值

描述

给你一个 有向图 ,它含有 n 个节点和 m 条边。节点编号从 0 到 n - 1 。

给你一个字符串 colors ,其中 colors[i] 是小写英文字母,表示图中第 i 个节点的 颜色 (下标从 0 开始)。同时给你一个二维数组 edges ,其中 edges[j] = [aj, bj] 表示从节点 aj 到节点 bj 有一条 有向边 。

图中一条有效 路径 是一个点序列 x1 -> x2 -> x3 -> ... -> xk ,对于所有 1 <= i < k ,从 xi 到 xi+1 在图中有一条有向边。路径的 颜色值 是路径中 出现次数最多 颜色的节点数目。

请你返回给定图中有效路径里面的 最大颜色值 。如果图中含有环,请返回 -1 。

示例 1:

6ddJXu

输入:colors = "abaca", edges = [[0,1],[0,2],[2,3],[3,4]] 输出:3 解释:路径 0 -> 2 -> 3 -> 4 含有 3 个颜色为 "a" 的节点(上图中的红色节点)。 示例 2:

4IMrd2

输入:colors = "a", edges = [[0,0]] 输出:-1 解释:从 0 到 0 有一个环。

提示:

n == colors.length m == edges.length 1 <= n <= 10^5 0 <= m <= 10^5 colors 只含有小写英文字母。 0 <= aj, bj < n

思路

拓扑排序加动态规划

  • 如果存在环则不存在拓扑排序。

  • 如果a->b,那么在拓扑排序中 b一定在a的后面,所以一条路径上点的顺序与拓扑排序的顺序是一致的。

  • bash dp[next][color]=Math.mac(dp[next][color],dp[cur][color])

代码

import java.util.*;

public class N4 {
    public int largestPathValue(String colors, int[][] edges) {
        final int n=colors.length();
        final char[] c=colors.toCharArray();
        List<Integer>[] graph=new List[n];
        for (int i=0;i<n;i++)graph[i]=new ArrayList<>();

        int[] in=new int[n];
        for (int[] e:edges){
            in[e[1]]++;
            graph[e[0]].add(e[1]);
        }

        int found=0;
        Queue<Integer> queue=new ArrayDeque<>(n);
        for (int i=0;i<in.length;i++){
            if(in[i]==0)queue.add(i);
        }
        int[][] dp=new int[n][26];
        while (!queue.isEmpty()){
            int cur=queue.poll();
            found++;
            dp[cur][c[cur]-'a']++;
            for (int next:graph[cur]){
                in[next]--;
                if(in[next]==0)queue.add(next);
                for (int i=0;i<26;i++){
                    dp[next][i]=Math.max(dp[cur][i],dp[next][i]);
                }
            }
            if(found>n)return -1;
        }
        if(found!=n)return -1;
        int res=0;
        for (int[] d:dp){
            for (int i:d)res=Math.max(i,res);
        }

        return res;

    }


}