力扣第236场周赛
题一 数组元素积的符号
描述
已知函数 signFunc(x) 将会根据 x 的正负返回特定值:
如果 x 是正数,返回 1 。 如果 x 是负数,返回 -1 。 如果 x 是等于 0 ,返回 0 。 给你一个整数数组 nums 。令 product 为数组 nums 中所有元素值的乘积。
返回 signFunc(product) 。
思路
本题可以转换成求负数个数。
代码
class Solution {
public int arraySign(int[] nums) {
int cnt1=0;
for (int i:nums)
{
if(i==0)return 0;
if(i<0)cnt1++;
}
if(cnt1%2==0)return 1;
return -1;
}
}
题二 找出游戏的获胜者
描述
共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。
游戏遵循如下规则:
从第 1 名小伙伴所在位置 开始 。 沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。 你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。 如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。 否则,圈子中最后一名小伙伴赢得游戏。 给你参与游戏的小伙伴总数 n ,和一个整数 k ,返回游戏的获胜者。
思路
- 看成队列
- 模拟游戏规则
代码
class Solution {
public int findTheWinner(int n, int k) {
Queue<Integer> queue=new ArrayDeque<>();
for (int i=1;i<=n;i++){
queue.add(i);
}
int cur=k;
while (queue.size()>1){
cur--;
int p=queue.poll();
if(cur!=0)queue.add(p);
else cur=k;
}
return queue.poll();
}
}
题三
描述
给你一个长度为 n 的 3 跑道道路 ,它总共包含 n + 1 个 点 ,编号为 0 到 n 。一只青蛙从 0 号点第二条跑道 出发 ,它想要跳到点 n 处。然而道路上可能有一些障碍。
给你一个长度为 n + 1 的数组 obstacles ,其中 obstacles[i] (取值范围从 0 到 3)表示在点 i 处的 obstacles[i] 跑道上有一个障碍。如果 obstacles[i] == 0 ,那么点 i 处没有障碍。任何一个点的三条跑道中 最多有一个 障碍。
比方说,如果 obstacles[2] == 1 ,那么说明在点 2 处跑道 1 有障碍。 这只青蛙从点 i 跳到点 i + 1 且跑道不变的前提是点 i + 1 的同一跑道上没有障碍。为了躲避障碍,这只青蛙也可以在 同一个 点处 侧跳 到 另外一条 跑道(这两条跑道可以不相邻),但前提是跳过去的跑道该点处没有障碍。
比方说,这只青蛙可以从点 3 处的跑道 3 跳到点 3 处的跑道 1 。 这只青蛙从点 0 处跑道 2 出发,并想到达点 n 处的 任一跑道 ,请你返回 最少侧跳次数 。
注意:点 0 处和点 n 处的任一跑道都不会有障碍。
思路
动态规划:
dp[number][idx] 表示 在number跑道的idx位置到终点最少还需要几次
代码
class Solution {
public int minSideJumps(int[] obstacles) {
int[][] dp=new int[3][obstacles.length];
for (int i=0;i<3;i++) Arrays.fill(dp[i],-1);
int res=slove(2, 0, obstacles, dp);
return res;
}
private int slove(int number, int idx, int[] obstacles, int[][] dp) {
if(dp[number-1][idx]!=-1)return dp[number-1][idx];
int res=Integer.MAX_VALUE>>1;
if(idx==obstacles.length-1)return 0;
if(obstacles[idx+1]!=number)res=slove(number,idx+1,obstacles,dp);
else {
for (int i=1;i<=3;i++)
{
if(obstacles[idx]==i||obstacles[idx+1]==i)continue;
res=Math.min(res,1+slove(i,idx,obstacles,dp));
}
}
return dp[number-1][idx]=res;
}
}
题四 求出 MK 平均值
描述
给你两个整数 m 和 k ,以及数据流形式的若干整数。你需要实现一个数据结构,计算这个数据流的 MK 平均值 。
MK 平均值 按照如下步骤计算:
如果数据流中的整数少于 m 个,MK 平均值 为 -1 ,否则将数据流中最后 m 个元素拷贝到一个独立的容器中。 从这个容器中删除最小的 k 个数和最大的 k 个数。 计算剩余元素的平均值,并 向下取整到最近的整数 。 请你实现 MKAverage 类:
MKAverage(int m, int k) 用一个空的数据流和两个整数 m 和 k 初始化 MKAverage 对象。 void addElement(int num) 往数据流中插入一个新的元素 num 。 int calculateMKAverage() 对当前的数据流计算并返回 MK 平均数 ,结果需 向下取整到最近的整数 。
思路
- 用4颗TreeSet树,一颗维护最小的K个值,一颗维护小的临时值,一颗维护最大的K个值,一颗维护最大的临时K个值。
- 临时值的两颗树存在的意义:用来存储未过期的值,在对应的小树和大树个树不够的时候补充。
- 用一个队列维护没有过期的值。
- 对最小树、最大树和队列操作的同时维护各自的sum。
代码
import java.util.*;
/**
* author: fangjie
* email: syfangjie@live.cn
* date: 2021/4/11 11:03 上午
*/
public class N4 {
//["MKAverage","addElement","addElement","calculateMKAverage","addElement","addElement","calculateMKAverage","addElement","addElement","calculateMKAverage","addElement"]
//[[3,1],[58916],[61899],[],[85406],[49757],[],[27520],[12303],[],[63945]]
public static void main(String[] args) {
MKAverage mkAverage = new MKAverage(3, 1);
mkAverage.addElement(58916);
mkAverage.addElement(61899);
System.out.println(mkAverage.calculateMKAverage());
mkAverage.addElement(85406);
mkAverage.addElement(49757);
System.out.println(mkAverage.calculateMKAverage());
mkAverage.addElement(27520);
mkAverage.addElement(12303);
System.out.println(mkAverage.calculateMKAverage());
mkAverage.addElement(63945);
}
}
class MKAverage {
private final int m;
private final int k;
private int sum;
private int size;
private Queue<int[]> queue;
private int minSum;
private TreeSet<int[]> min;
private TreeSet<int[]> minT;
private int maxSum;
private TreeSet<int[]> max;
private TreeSet<int[]> maxT;
public MKAverage(int m, int k) {
this.m=m;
this.k=k;
this.sum=this.maxSum=this.minSum=this.size=0;
this.queue=new ArrayDeque<>();
min=new TreeSet<>((o1, o2) -> {
if(o1[0]==o2[0])return Integer.compare(o1[1],o2[1]);
return Integer.compare(o1[0],o2[0]);
});
minT=new TreeSet<>((o1, o2) -> {
if(o1[0]==o2[0])return Integer.compare(o1[1],o2[1]);
return Integer.compare(o1[0],o2[0]);
});
max=new TreeSet<>((o1, o2) -> {
if(o1[0]==o2[0])return Integer.compare(o1[1],o2[1]);
return Integer.compare(o2[0],o1[0]);
});
maxT=new TreeSet<>((o1, o2) -> {
if(o1[0]==o2[0])return Integer.compare(o1[1],o2[1]);
return Integer.compare(o2[0],o1[0]);
});
}
public void addElement(int num) {
size++;
int[] cur = {num, size};
sum+=num;
queue.add(cur);
if(queue.size()>m){
int[] c = queue.poll();
sum-=c[0];
minT.remove(c);
if(min.remove(c))minSum-=c[0];
maxT.remove(c);
if(max.remove(c))maxSum-=c[0];
}
minSum+=help(min,minT,cur);
maxSum+=help(max,maxT,cur);
}
private int help(TreeSet<int[]> set,TreeSet<int[]>tSet,int[] cur){
int res=0;
while (set.size()<k&&!tSet.isEmpty()){
int[] c=tSet.pollFirst();
res+=c[0];
set.add(c);
}
set.add(cur);
res+=cur[0];
while (set.size()>k){
int[] c=set.pollLast();
res-=c[0];
tSet.add(c);
}
return res;
}
public int calculateMKAverage() {
if(queue.size()<m)return -1;
//System.out.println(Arrays.toString(new int[]{sum,minSum,maxSum}));
return (sum-minSum-maxSum)/(m-2*k);
}
}
/**
* Your MKAverage object will be instantiated and called as such:
* MKAverage obj = new MKAverage(m, k);
* obj.addElement(num);
* int param_2 = obj.calculateMKAverage();
*/
/*