难度简单0
给你一个下标从 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) {
Set<Character> set = new HashSet<>();
set.add('a'); set.add('e'); set.add('i'); set.add('o'); set.add('u');
int res = 0;
for(int i = left; i <= right && i < words.length; i++){
String word = words[i];
if(set.contains(word.charAt(0)) && set.contains(word.charAt(word.length()-1))){
res++;
}
}
return res;
}
}
难度中等4
给你一个下标从 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 <= 105
-106 <= nums[i] <= 106
class Solution {
public int maxScore(int[] nums) {
int res = 0; // 正整数的个数
double sum = 0;
Arrays.sort(nums);
for(int i = nums.length-1; i >= 0; i--){
sum += nums[i];
if(sum > 0) res++;
}
return res;
}
}
难度中等16
给你一个下标从 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 <= 105
0 <= nums[i] <= 106
class Solution {
// 减去2^k 相当于把位上的1变成0
// 每次修改同一个比特位的1 ==> 异或操作
// 求 异或和=0 的子数组个数
// 两个前缀和的异或 ==> 两个前缀和是相等的
// 前缀和数组中所有相同的数对
public long beautifulSubarrays(int[] nums) {
long res = 0;
int n = nums.length;
int[] s = new int[n+1];
for(int i = 0; i < n; i++){
s[i+1] = s[i] ^ nums[i];
}
// 记录左边前缀和出现次数
Map<Integer, Integer> cnt = new HashMap<>();
for(int x : s){
// 先计入答案再统计个数,如果反过来的话,就相当于把空子数组也计入答案了
res += cnt.getOrDefault(x, 0);
cnt.merge(x, 1, Integer:: sum);
// 上面merge写法等于:cnt.put(x, cnt.getOrDefault(x, 0) + 1);
}
return res;
}
}
一边计算前缀和s
,一边计算答案
class Solution {
// 减去2^k 相当于把位上的1变成0
// 每次修改同一个比特位的1 ==> 异或操作
// 求 异或和=0 的子数组个数
// 两个前缀和的异或 ==> 两个前缀和是相等的
// 前缀和数组中所有相同的数对
public long beautifulSubarrays(int[] nums) {
long res = 0;
int n = nums.length;
int s = 0;
// 记录左边前缀和出现次数
Map<Integer, Integer> cnt = new HashMap<>();
cnt.put(s, 1); // s[0]
for(int x : nums){
s = s ^ x;
res += cnt.getOrDefault(s, 0);
//cnt.merge(x, 1, Integer:: sum);
cnt.put(s, cnt.getOrDefault(x, 0) + 1);
}
return res;
}
}
难度困难18
你有一台电脑,它可以 同时 运行无数个任务。给你一个二维整数数组 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
class Solution {
public int findMinimumTime(int[][] tasks) {
// 根据区间右端点排序,这样能充分利用区间
Arrays.sort(tasks, (a, b) -> a[1] - b[1]);
int res = 0;
// run表示当前正在运行中的时刻(区间)
boolean[] run = new boolean[tasks[tasks.length-1][1] + 1];
for(int[] 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;
++res;
}
}
}
return res;
}
}