LeetCode 336周赛


6315. 统计范围内的元音字符串数

给你一个下标从 0 开始的字符串数组 words 和两个整数:left 和 right 。

如果字符串以元音字母开头并以元音字母结尾,那么该字符串就是一个 元音字符串 ,其中元音字母是 'a''e''i''o''u' 。

返回 words[i] 是元音字符串的数目,其中 i 在闭区间 [left, right] 内。

 

示例 1:

输入:words = ["are","amy","u"], left = 0, right = 2
输出:2
解释:
- "are" 是一个元音字符串,因为它以 'a' 开头并以 'e' 结尾。
- "amy" 不是元音字符串,因为它没有以元音字母结尾。
- "u" 是一个元音字符串,因为它以 'u' 开头并以 'u' 结尾。
在上述范围中的元音字符串数目为 2 。
示例 2:

输入:words = ["hey","aeo","mu","ooo","artro"], left = 1, right = 4
输出:3
解释:
- "aeo" 是一个元音字符串,因为它以 'a' 开头并以 'o' 结尾。
- "mu" 不是元音字符串,因为它没有以元音字母开头。
- "ooo" 是一个元音字符串,因为它以 'o' 开头并以 'o' 结尾。
- "artro" 是一个元音字符串,因为它以 'a' 开头并以 'o' 结尾。
在上述范围中的元音字符串数目为 3 。
 

提示:

1 <= words.length <= 1000
1 <= words[i].length <= 10
words[i] 仅由小写英文字母组成
0 <= left <= right < words.length

解答:

class Solution {
       // 计算给定单词范围内元音字符串的数量
    public int vowelStrings(String[] words, int left, int right) {
        int count = 0;
        for (int i = left; i <= right; i++) {
            String word = words[i];
            if (isVowelString(word)) {
                count++;
            }
        }
        return count;
    }
    // 检查给定字符串是否为元音字符串
    private boolean isVowelString(String word) {
        char first = word.charAt(0);
        char last = word.charAt(word.length() - 1);
        return isVowel(first) && isVowel(last);
    }
    // 检查给定字符是否为元音字母
    private boolean isVowel(char c) {
        return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
    }
}

6316. 重排数组以得到最大前缀分数

给你一个下标从 0 开始的整数数组 nums 。你可以将 nums 中的元素按 任意顺序 重排(包括给定顺序)。

令 prefix 为一个数组,它包含了 nums 重新排列后的前缀和。换句话说,prefix[i] 是 nums 重新排列后下标从 0 到 i 的元素之和。nums 的 分数 是 prefix 数组中正整数的个数。

返回可以得到的最大分数。

示例 1:

输入:nums = [2,-1,0,1,-3,3,-3]
输出:6
解释:数组重排为 nums = [2,3,1,-1,-3,0,-3] 。
prefix = [2,5,6,5,2,2,-1] ,分数为 6 。
可以证明 6 是能够得到的最大分数。
示例 2:

输入:nums = [-2,-3,0]
输出:0
解释:不管怎么重排数组得到的分数都是 0 。
 

提示:

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

解答:贪心,排序从后往前枚举,定义的sum必须是long类型,比赛因为这个wa了一次

class Solution {
    public int maxScore(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        int res=0;
        long sum=0;
        for (int i = n-1; i >=0; i--) {
           sum+=nums[i];
           if(sum<=0)return res;
           res++;
        }
        return res;
    }
}

6317. 统计美丽子数组数目

给你一个下标从 0 开始的整数数组nums 。每次操作中,你可以:

选择两个满足 0 <= i, j < nums.length 的不同下标 i 和 j 。
选择一个非负整数 k ,满足 nums[i] 和 nums[j] 在二进制下的第 k 位(下标编号从 0 开始)是 1 。
将 nums[i] 和 nums[j] 都减去 2k 。
如果一个子数组内执行上述操作若干次后,该子数组可以变成一个全为 0 的数组,那么我们称它是一个 美丽 的子数组。

请你返回数组 nums 中 美丽子数组 的数目。

子数组是一个数组中一段连续 非空 的元素序列。

示例 1:

输入:nums = [4,3,1,2,4]
输出:2
解释:nums 中有 2 个美丽子数组:[4,3,1,2,4][4,3,1,2,4] 。
- 按照下述步骤,我们可以将子数组 [3,1,2] 中所有元素变成 0 :
  - 选择 [3, 1, 2] 和 k = 1 。将 2 个数字都减去 21 ,子数组变成 [1, 1, 0] 。
  - 选择 [1, 1, 0] 和 k = 0 。将 2 个数字都减去 20 ,子数组变成 [0, 0, 0] 。
- 按照下述步骤,我们可以将子数组 [4,3,1,2,4] 中所有元素变成 0 :
  - 选择 [4, 3, 1, 2, 4] 和 k = 2 。将 2 个数字都减去 22 ,子数组变成 [0, 3, 1, 2, 0] 。
  - 选择 [0, 3, 1, 2, 0] 和 k = 0 。将 2 个数字都减去 20 ,子数组变成 [0, 2, 0, 2, 0] 。
  - 选择 [0, 2, 0, 2, 0] 和 k = 1 。将 2 个数字都减去 21 ,子数组变成 [0, 0, 0, 0, 0] 。
示例 2:

输入:nums = [1,10,4]
输出:0
解释:nums 中没有任何美丽子数组。
 

提示:
1 <= nums.length <= 10^5
0 <= nums[i] <= 10^6

解答:哈希表存储,sum异或每一个数,sum为0和不为0分开计数。

class Solution {
    public long beautifulSubarrays(int[] nums) {
        long res=0;
        int n=nums.length;
        Map<Long,Integer> map=new HashMap<>();
        long sum=0;
        for(int i=0;i<nums.length;i++){
            sum^=nums[i];
            if(map.containsKey(sum)){
                   //sum为0的话多+1,因为本身也算一个
                    if(sum==0){
                        res+=map.get(sum)+1;
                        map.put(sum,map.get(sum)+1);
                    }
                    else{
                        res+=map.get(sum);
                        map.put(sum,map.get(sum)+1);
                    }
            }
            else{
                map.put(sum,1);
                if(sum==0)res++;
            }
        }
        if(map.containsKey(0))res+=map.get(0);
        return res;
    }
}

6318. 完成所有任务的最少时间

你有一台电脑,它可以 同时 运行无数个任务。给你一个二维整数数组 tasks ,其中 tasks[i] = [starti, endi, durationi] 表示第 i 个任务需要在 闭区间 时间段 [starti, endi] 内运行 durationi 个整数时间点(但不需要连续)。

当电脑需要运行任务时,你可以打开电脑,如果空闲时,你可以将电脑关闭。

请你返回完成所有任务的情况下,电脑最少需要运行多少秒。

示例 1:

输入:tasks = [[2,3,1],[4,5,1],[1,5,2]]
输出:2
解释:
- 第一个任务在闭区间 [2, 2] 运行。
- 第二个任务在闭区间 [5, 5] 运行。
- 第三个任务在闭区间 [2, 2][5, 5] 运行。
电脑总共运行 2 个整数时间点。
示例 2:

输入:tasks = [[1,3,2],[2,5,3],[5,6,2]]
输出:4
解释:
- 第一个任务在闭区间 [2, 3] 运行
- 第二个任务在闭区间 [2, 3][5, 5] 运行。
- 第三个任务在闭区间 [5, 6] 运行。
电脑总共运行 4 个整数时间点。
 

提示:
1 <= tasks.length <= 2000
tasks[i].length == 3
1 <= starti, endi <= 2000
1 <= durationi <= endi - starti + 1

解答:

  • 按照右端点排序
  • 对于 tasks[i] 来说,它右侧的任务要么和它没有交集,要么包含它的区间后缀
  • 遍历排序后的任务,先统计区间内的电脑运行时间点,如果个数小于duration,则尽量把运行时间点安排在区间 [start,end]的后缀上。
class Solution {
    public int findMinimumTime(int[][] tasks) {
        Arrays.sort(tasks, (a, b) -> a[1] - b[1]);
        int ans = 0;
        var run = new boolean[2001];
        for (var t : tasks) {
            int start = t[0], end = t[1], d = t[2];
            for (int i = start; i <= end; ++i)
                if (run[i]) --d;  // 统计已经是运行中的时间点
            for (int i = end; d > 0; --i) // 剩余的 d 填充区间后缀
                if (!run[i]) {
                    run[i] = true;
                    --d;
                    ++ans;
                }
        }
        return ans;
    }
}

  目录