A. 判断句子是否为全字母句
题目描述:
全字母句指的是字符串中’a’~'z’全部出现至少一遍,判断一个字符串是否为全字母句。
分析:
遍历一遍’a’~'z’即可,若某个字母没有出现则返回false。
class Solution {
public boolean checkIfPangram(String sentence) {
char[] c = new char[]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for(int i=0;i<26;i++){
if(sentence.indexOf(c[i])==-1)
return false;
}
return true;
}
}
B. 雪糕的最大数量
题目描述:
商店中新到 n 支雪糕,用长度为 n 的数组 costs 表示雪糕的定价,其中 costs[i] 表示第 i 支雪糕的现金价格。Tony 一共有 coins 现金可以用于消费,他想要买尽可能多的雪糕。
给你价格数组 costs 和现金量 coins ,请你计算并返回 Tony 用 coins 现金能够买到的雪糕的 最大数量 。
注意:Tony 可以按任意顺序购买雪糕。
分析:
一开始还以为是动态规划模板题,读了一遍才发现是典型的贪心,尽可能地去买最便宜的就好了,直到买不下为止。注意下临界条件。
class Solution {
public int maxIceCream(int[] costs, int coins) {
Arrays.sort(costs);
int sum = 0;
for(int i=0;i<costs.length;i++){
if(sum+costs[i]<=coins){
sum += costs[i];
}else
return i;
}
return costs.length;
}
}
C. 单线程 CPU
题目描述:
给你一个二维数组 tasks ,用于表示 n 项从 0 到 n - 1 编号的任务。其中 tasks[i] = [enqueueTimei, processingTimei] 意味着第 i 项任务将会于 enqueueTimei 时进入任务队列,需要 processingTimei 的时长完成执行。
现有一个单线程 CPU ,同一时间只能执行 最多一项 任务,该 CPU 将会按照下述方式运行:
如果 CPU 空闲,且任务队列中没有需要执行的任务,则 CPU 保持空闲状态。
如果 CPU 空闲,但任务队列中有需要执行的任务,则 CPU 将会选择 执行时间最短 的任务开始执行。如果多个任务具有同样的最短执行时间,则选择下标最小的任务开始执行。
一旦某项任务开始执行,CPU 在 执行完整个任务 前都不会停止。
CPU 可以在完成一项任务后,立即开始执行一项新任务。
返回 CPU 处理任务的顺序。
分析:
- 每一个任务实际有3个参数,分别是编号、到达时间和持续时间,可以把它抽象成一个Task类。(为了编程方便而已)
- 由题目得到,若cpu空闲,优先选择时间最短的任务(时间相同时取下标最短的),把这个优先条件描述成一个比较器Comparator1。(稳定性排序)
- 脑内模拟一遍,能进行选取的集合元素也是随着时间的进行而不断变化的,要在变化中每次基于这个Comparator1取出最优的,那就很容易想到堆(优先队列)。
- 既然选择了使用优先队列,那么就考虑入队和出队的条件。只要入队了,就有可能被cpu选中,那么入队的条件只有一个,那就是它的到达时间大于当前时间。保证了队内的元素都满足这个条件,那么按照Comparator1排序规则出队的那个一定是当前cpu的执行目标。出队很好写,问题是入队,不管cpu怎么选择,所有的task的入队顺序应该是确定不变的,即入队的时刻大小的排序(同时刻前后关系可以忽略),用指针记录这个下一个该谁入队了,当当前时刻等于指针时就让它入队,并把指针+1。
- 当然这么做是很耗时的,有两个地方需要优化。第一,指针不必一个一个加,因为只有当cpu空闲时才有可能发生出队,因此在cpu空闲出队前入队即可,可以让指针直接”快进“到cpu空闲的时刻,把过去的这段时间内的Task一次入队。第二,cpu不空闲时,也没必要入队出队操作,所以任务进入cpu后可以直接给时间加上这个任务的执行时间。总之,会发生入队出队变化的仅仅会发生在cpu刚空闲即可。
这道题本质还是模拟+优化。
class Solution {
class Task{//将任务抽象为对象
int i;//编号
int begin;//到达时间
int time;//执行时间
Task(int i,int begin,int time){
this.i = i;
this.begin = begin;
this.time = time;
}
}
public int[] getOrder(int[][] tasks) {
int[] res = new int[tasks.length];//方法的返回数组
//将所有的Task按到达时间排序
List<Task> list = new ArrayList<>();
for(int i=0;i<tasks.length;i++)
list.add(new Task(i,tasks[i][0],tasks[i][1]));
list.sort(new Comparator<Task>() {
@Override
public int compare(Task o1, Task o2) {
return o1.begin-o2.begin;
}
});
int index = 0;//标记list里已经入队到哪一个了
//创建优先队列,相当于cpu的“阻塞队列”,从中选取最合适的任务
Queue<Task> queue = new PriorityQueue<Task>(new Comparator<Task>() {
@Override
public int compare(Task o1, Task o2) {
if(o1.time!=o2.time)
return o1.time-o2.time;
else{
return o1.i-o2.i;
}
}
});
int t = 1;//题目要求的时间是从1开始的,不是0
int cnt = 0;//已经执行的任务数
while(true){//每一次循环都相当于cpu空闲一次
//检查是否有入队任务,如果有的话将能入队的一次性入队
while(index<list.size()&&list.get(index).begin<=t){
queue.add(list.get(index));
index++;
}
//CPU空闲且优先队列为空的情况,快进到下一个能入队的起始时间
if(queue.size()==0){
t = list.get(index).begin;
continue;
}
//出队元素,赋值,快进到下一次cpu空闲
Task task = queue.poll();
res[cnt++] = task.i;
if(cnt==tasks.length)
break;
t += task.time;
}
return res;
}
}
D. 所有数对按位与结果的异或和
题目描述:
列表的 异或和(XOR sum)指对所有元素进行按位 XOR 运算的结果。如果列表中仅有一个元素,那么其 异或和 就等于该元素。
例如,[1,2,3,4] 的 异或和 等于 1 XOR 2 XOR 3 XOR 4 = 4 ,而 [3] 的 异或和 等于 3 。
给你两个下标 从 0 开始 计数的数组 arr1 和 arr2 ,两数组均由非负整数组成。
根据每个 (i, j) 数对,构造一个由 arr1[i] AND arr2[j](按位 AND 运算)结果组成的列表。其中 0 <= i < arr1.length 且 0 <= j < arr2.length 。
返回上述列表的 异或和 。
分析:
- 最暴力的方法,按照题意模拟即可,当然会超时。先进行O(mn)的and运算,获得mn个元素,再进行(m*n-1)次的xor运算,总的算法复杂度是O(2mn-1)=O(mn)
- 考虑到是二进制运算,且传入参数为整形变量,我们可以对整形的最大32位分别求结果,具体方法为方法一中的mn个元素,我们不关心这些元素具体是多少,只关心它在第i位上是1的元素有多少个(i指的是0~31)。而and运算结果为1就要求两个加数都为1,相当于分别求arr1和arr2中元素在第i位上为1的个数。就比如arr1有5个数在第i位,arr2有6个,那么arr1与arr2的交叉相乘后肯定有30个数在i位上是1。考虑到xor的性质,如果是偶数个数的异或和,那结果一定是0,如果是奇数则为1。所以这个第i位肯定是0.同理i再取0到31的其他值,算出最终结果的二进制,转换为十进制即可。算法复杂度为(32(m+n)),对每一位,只用判断m+n个元素在该位是否为1,代码中的a1[i] * a2[i] % 2实际也只会带入最后一位进行计算进行取余。
public class Solution {
public int getXORSum(int[] arr1, int[] arr2) {
StringBuilder r= new StringBuilder();
int[] a1 = new int[32];
int[] a2 = new int[32];
count(arr1, a1);
count(arr2, a2);
for(int i=31;i>=0;i--)
r.append(a1[i] * a2[i] % 2);
return Integer.parseInt(r.toString(),2);
}
private void count(int[] arr, int[] a2) {
for(int e:arr){
String s = Integer.toBinaryString(e);
for(int i=0;i<s.length();i++){
if(s.charAt(s.length()-i-1)=='1')
a2[i]++;
}
}
}
}