这次周赛整体感觉下来难度是不高的,前三题我都用模拟解决了,但是在解决问题的过程中,碰到一些细节方面总是卡壳,比如第一题就卡了二十几分钟,这是不达标的,整个算法题感还没有完全培养上来,还需要在之后的刷题过程中,理清思路,顺流而下。
直接模拟就好,我的ac垃圾题解如下,在while里面还加了这么多判断,突出一个乱写。
class Solution {
public int[] answerQueries(int[] nums, int[] queries) {
int qlen=queries.length;
int[]ans=new int[qlen];
Arrays.sort(nums);
for(int i=0;i<qlen;i++){
long target=queries[i];
long res=0;
int reslen=0;
int j=0;
while(reslen<nums.length&&res<=target){
res+=nums[reslen++];
if(res>target){
reslen--;
break;
}
if(res==target) break;
}
ans[i]=reslen;
}
return ans;
}
}
参考TsReaper的题解模拟,先排序,然后就是两层循环,外层循环queries,内层循环nums,内层循环一直加到最后一个数字,提前退出条件就是当前和res已经大于target了,如果一直没有退出,则说明整个数组都可以。
class Solution {
public int[] answerQueries(int[] nums, int[] queries) {
Arrays.sort(nums);
int qLen=queries.length;
int numLen=nums.length;
int[]ans=new int[qLen];
for(int q=0;q<qLen;q++){
long res=0;
for(int i=0;i<numLen;i++){
res+=nums[i];
if(res>queries[q]){
ans[q]=i;
break;
}
}
if(res<=queries[q])ans[q]=numLen;
}
return ans;
}
}
T2没什么好说的,直接栈模拟就好了,可以直接用StringBuilder容器模拟,其中删除的api为sb.deleteCharAt(int index)、获取长度为sb.length();
先贴上我的垃圾ac题解,又臭又长,先是一层循环,把每个种类出现垃圾的地方标出来了,并且把每种垃圾的总和分别计算出来,然后第二次遍历计算前缀和方便自己计算路程,第三次遍历把end求出来,方便利用前缀和求路程。
class Solution {
public int garbageCollection(String[] garbage, int[] travel) {
int res=0;
int garlen=garbage.length;
int tralen=travel.length;
boolean[][]exit=new boolean[garlen][3];
int[]trash=new int[3];
int[]road=new int[3];
for(int i=0;i<garlen;i++){
String g=garbage[i];
for(int j=0;j<g.length();j++){
if(g.charAt(j)=='M'){
exit[i][0]=true;
trash[0]++;
}
if(g.charAt(j)=='P'){
exit[i][1]=true;
trash[1]++;
}
if(g.charAt(j)=='G'){
exit[i][2]=true;
trash[2]++;
}
}
}
int[]preSum=new int[garlen];
for(int i=0;i<tralen;i++){
preSum[i+1]=preSum[i]+travel[i];
}
for(int i=0;i<3;i++){
int end=-1;
for(int j=0;j<garlen;j++){
if(exit[j][i]==true){
end=j;
}
}
if(end!=-1)res+=preSum[end];
}
res+=trash[0]+trash[1]+trash[2];
return res;
}
}
参考灵神的题解才是简约,只用两次遍历,第一次遍历中,不管什么垃圾,全部加起来就是总垃圾处理时间,并且从上面可以看出,路程我们只需要知道每种类别出现垃圾的最后位置就可以了,因此只需要不断记录一下终点位置。
超简约python题解如下:
class Solution:
def garbageCollection(self, garbage: List[str], travel: List[int]) -> int:
ans=0
# 记录最后一次出现位置
end=[0]*3
for index, g in enumerate(garbage):
ans += len(g)
for j, c in enumerate("MPG"):
# 记录最后一次位置
if c in g:
end[j]=index
# 将三种垃圾的所有路程加起来
return ans+sum(sum(travel[:e])for e in end)
知道需要排出一个先后顺序,但不知道采用什么算法,后来参考灵神的题解,知道拓扑排序能够排出元素的相对顺序,而自己之前恰好做过这方面的内容,引路算法学习-拓扑排序。由于行和列是互不影响的,因此可以分别对他们进行拓扑排序。在已经排序的情况下,通过字典标号,在结果矩阵中进行填充。
class Solution {
public int[][] buildMatrix(int k, int[][] rowConditions, int[][] colConditions) {
int[]rowTopo=topoSort(k,rowConditions);
int[]colTopo=topoSort(k,colConditions);
//没有同时满足限制的
if(rowTopo.length!=k||colTopo.length!=k) return new int[][]{};
//先指定数字的col位置,前面的数字应该列号小,以数组进行字典映射,key数字-value列号
int[]pos=new int[k];
for(int i=0;i<k;i++){
pos[colTopo[i]]=i;
}
int[][]ans=new int[k][k];
//从row=0开始一行一行排列,前面的数字row[i]应该行号小
for(int i=0;i<k;i++){
ans[i][pos[rowTopo[i]]]=rowTopo[i]+1;
}
return ans;
}
public int[] topoSort(int k,int[][]map){
ArrayList<Integer>[] g=new ArrayList[k];
//初始化g中所有的HashSet<>();
Arrays.setAll(g,e->new ArrayList<Integer>());
int[]inD=new int[k];
for(int[]m:map){
//顶点编号从0开始
g[m[0]-1].add(m[1]-1);
inD[m[1]-1]++;
}
ArrayDeque<Integer> que=new ArrayDeque<>();
for(int i=0;i<k;i++){
if(inD[i]==0) que.add(i);
}
ArrayList<Integer> res=new ArrayList<>();
while(!que.isEmpty()){
int top=que.poll();
res.add(top);
for(int i:g[top]){
if(--inD[i]==0) que.offer(i);
}
}
//ArrayList转int[]
return res.stream().mapToInt(x->x).toArray();
}
}