周赛链接 :https://leetcode-cn.com/contest/weekly-contest-237
本次周赛还是比较简单的,奈何自己太菜了,哈哈哈哈哈。
5734. 判断句子是否为全字母句 https://leetcode-cn.com/contest/weekly-contest-237/problems/check-if-the-sentence-is-pangram/
这道题十分简单,即判断英文字符串是否包含全部的26个小写英文字母,使用长度为26的boolean数组用于存储是否包含a~z的英文字符是否在字符串中出现过,出现过即设为true,最终遍历数组若出现某一位置为false的情况,即返回fakse。代码如下:
class Solution {
public boolean checkIfPangram(String sentence) {
if(sentence.length() < 26){
return false;
}
boolean[] flags = new boolean[26];
for(char c : sentence.toCharArray()){
flags[c - 'a'] = true;
}
for(boolean flag : flags){
if(!flag){
return false;
}
}
return true;
}
}
5735. 雪糕的最大数量 https://leetcode-cn.com/contest/weekly-contest-237/problems/maximum-ice-cream-bars/
这道题也是送分题,想要求得可以购买雪糕的最大数量,将雪糕的花费costs数组排序,从低价雪糕开始买,什么时候剩余的前不够就达到最大的数量了。代码如下:
class Solution {
public int maxIceCream(int[] costs, int coins) {
int res = 0;
Arrays.sort(costs);
for(int cost : costs){
if(coins < cost){
return res;
}
coins -= cost;
res++;
}
return res;
}
}
5736. 单线程 CPU https://leetcode-cn.com/contest/weekly-contest-237/problems/single-threaded-cpu/
这道题给的题目信息挺明确的,做的时候却琢磨了半天。有思路但是代码实现的时候分了一点劲。总结一点经验:在竞赛的时候java成熟的数据结构随时可以使用的哈,节省时间且思路明确!!!!
首先我们知道了一系列的任务信息,他们将在指定的时间到达任务队列等待CPU的调度。
影响CPU调度的因素有:
1、任务到达时间(先来后到FIFO);
2、任务执行时间(等待队列内部是耗时时间少的任务优先执行,即使某任务在等待队列内等待时间已经很长,但执行耗时过长的话也会优先安排后到的任务先执行);
3、CPU是否被占用(某一任务即使在等待队列头部,而CPU正在执行某一任务,在CPU内的调度任务执行完成后,新到来的任务可能因为执行时间更短而排在队列头部或直接执行)。
一个任务到达时会有多种情况:
1、CPU空闲,此时等待队列即为空,任务可以直接执行;
2、CPU繁忙,任务插入等待队列;
代码实现思路:
1、我们忽略任务在CPU空闲的情况下,新到达的任务直接调度,可以将它转变为新到达的任务统一进入等待队列,CPU每次从队列头部取出一条任务;
2、新到达的任务根据其执行耗时可能插入值队列的头部、中部和尾部,需要时刻保证队列按照执行耗时排序(相同耗时时再按照FIFO的顺序);
3、CPU调度某一任务开始至结束的过程中,可能会有新到来的任务进入等待队列:我们可以在这一任务调度完完成后再将这之间新到达的任务放入队列。
代码实现如下:
实现1:
public int[] getOrder(int[][] tasks) {
int n = tasks.length;
for (int i = 0; i < n; i++){
// 记录原有的位置
tasks[i] = new int[]{tasks[i][0], tasks[i][1], i};
}
// 将任务按照到达时间进行排序
Arrays.sort(tasks, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
// 按任务进入时间排序
return Integer.compare(o1[0],o2[0]);
}
});
int[] res = new int[n];
int i = 0, currTime = 0, pos = 0;
// 使用LinkedList作为等待队列
LinkedList<Integer> queue = new LinkedList<>();
while (i < n || !queue.isEmpty()){
while (i < n && tasks[i][0] <= currTime){
if (queue.isEmpty()){
queue.push(i++);
} else {
int j = 0;
// 1.按照任务执行耗时排序
// 2.相同耗时按照任务先来后到排序
while (j < queue.size() && (tasks[queue.get(j)][1] < tasks[i][1] || tasks[queue.get(j)][1] == tasks[i][1] && tasks[queue.get(j)][2] < tasks[i][2])){
j++;
}
queue.add(j, i++);
}
}
if (!queue.isEmpty()){
// 从队列中取出一个任务执行
int index = queue.poll();
currTime += tasks[index][1];
res[pos++] = tasks[index][2];
}else if (i < n){ // queue.isEmpty()
// 更新当前时间
currTime = tasks[i][0];
}
}
return res;
}
大眼一看,使用了LinkedList,空间复杂度为O(n),一次归并排序和一次顺序遍历,时间复杂度总体为O(nlogn)。代码一运行,值跑出了大部分测试用例,超时了。
分析了一下代码,为了将新到达的任务放入队列中指定的位置,每次需要顺序遍历队列,加上外层任务数组的顺序遍历,这部分的时间复杂度是可以达到O(n2)的。
为了减少时间复杂度,我使用了小顶堆自动维护顺序,从而使时间复杂度达到了O(nlogn),顺利走完测试用例。
实现2:
public int[] getOrder1(int[][] tasks) {
int n = tasks.length;
for (int i = 0; i < n; i++){
/// 记录原有的位置
tasks[i] = new int[]{tasks[i][0], tasks[i][1], i};
}
// 将任务按照到达时间进行排序
Arrays.sort(tasks, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
// 按任务进入时间排序
return Integer.compare(o1[0],o2[0]);
}
});
int[] res = new int[n];
int i = 0, currTime = 0, pos = 0;
// 使用PriorityQueue作为等待队列
PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
// 1.按照任务执行耗时排序
// 2.相同耗时按照任务先来后到排序
int res = Integer.compare(tasks[i1][1], tasks[i2][1]); // 先比较耗时
if (res == 0){
return Integer.compare(tasks[i1][2], tasks[i2][2]); // 再比较任务到达时间
}
return res;
}
});
while (i < n || !queue.isEmpty()){
while (i < n && tasks[i][0] <= currTime){
// 往小顶堆添加任务
queue.offer(i++);
}
if (!queue.isEmpty()){
int index = queue.poll();
currTime += tasks[index][1];
res[pos++] = tasks[index][2];
}else if (i < n){ // queue.isEmpty()
currTime = tasks[i][0];
}
}
return res;
}
5737. 所有数对按位与结果的异或和 https://leetcode-cn.com/contest/weekly-contest-237/problems/find-xor-sum-of-all-pairs-bitwise-and/
这道题其实没有达到hard的程度。
只需要知道两点:
1、0 与任何数异或都为原值;
2、(a & b) ^ (a & c) = a & (b ^ c) ,就是分配律
代码如下:
class Solution {
public int getXORSum(int[] arr1, int[] arr2) {
int xorNum = 0;
for(int num : arr2){
xorNum ^= num;
}
int res = 0;
for(int num : arr1){
res ^= num & xorNum;
}
return res;
}
}