一,3158. 求出出现两次数字的 XOR 值
本题是一道纯模拟题,直接暴力。
代码如下:
class Solution {
public int duplicateNumbersXOR(int[] nums) {
int ans = 0;
long t = 0;
for(int x : nums){
if(((t>>x)&1) == 1){
ans ^= x;
}else{
t |= (1L<<x);
}
}
return ans;
}
}
二,3159. 查询数组中元素的出现位置
本题也是一道模拟题,可以先用一个集合记录nums数组中 x 出现的下标,再枚举queries数组,如果queries[i]大于集合的大小(即数组中x出现的次数小于queries[i]),返回-1;否则放回下标。
代码如下:
class Solution {
public int[] occurrencesOfElement(int[] nums, int[] queries, int x) {
List<Integer> lst = new ArrayList<>();
for(int i=0; i<nums.length; i++){
if(nums[i] == x){
lst.add(i);
}
}
int[] ans = new int[queries.length];
int i = 0;
for(int q : queries){
ans[i++] = lst.size() >= q ? lst.get(q-1) : -1;
}
return ans;
}
}
三,3160. 所有球里面不同颜色的数目
本题求每次操作后,不同颜色的数目,可以使用两个哈希表m1、m2,m1存储<i,i 的颜色>,m2存储<i 的颜色,该颜色的出现次数>。
接下来就是分情况讨论,当把球 x 的颜色改成 y 时:
- 如果 x 没有在之前出现过(即 m1.containsKey(x) == false),直接将<x,y>放入m1,将m2中的 y 颜色加1
- 如果 x 在之前出现过(即 m1.containsKey(x) == true),我们需要先将之前 x 对应的 z 颜色(即m1.get(x))的数目减一,如果减完之后 z 颜色的数量为 0,需要去除 z 颜色;如果不为0,就不去除。最后将<x,y>放入m1,将m2中的 y 颜色加1
- 完成一次上述操作后,ans[i] = m2.size()
代码如下:
class Solution {
public int[] queryResults(int limit, int[][] queries) {
int[] ans = new int[queries.length];
Map<Integer, Integer> m1 = new HashMap<>();//<i,i的颜色>
Map<Integer, Integer> m2 = new HashMap<>();//<i的颜色,该颜色出现次数>
for(int i=0; i<queries.length; i++){
int[] x = queries[i];
if(m1.containsKey(x[0]) && m2.merge(m1.get(x[0]), -1, Integer::sum)==0){
m2.remove(m1.get(x[0]));
}
m1.put(x[0], x[1]);
m2.merge(x[1], 1, Integer::sum);
ans[i] = m2.size();
}
return ans;
}
}
四,3161. 物块放置查询
由题目可知,我们需要一个数据结构来动态维护一个区域内的最大可放置的物块大小。满足以上条件的数据结构就是线段树:
- 如何进行点更新(update)?
- 假设我们要在 x 处放一个障碍物,pre 是 x 前一个障碍物,就需要更新以 x 为右端点时可以放置的最大物块,更新为 x - pre;nxt 是 x 后一个障碍物,同时我们还需要更新以 nxt 为右端点时可以放置的最大物块,更新为 nxt - x。
- 如何查询(query)?
- 我们查询的右端点有两种情况:1、刚好在障碍物上,直接查询[0,q[1]] 这块区域的最大值;2、不在障碍物上,那么就需要分成两段来求:一段是[0,pre]的最大值,另一段直接求就是 x - pre
class Solution {
int[] t;
//[l, r]表示当前的范围,i表示数组t存储[l,r]的最大值的下标
//jobr表示要更新端点,val表示更新的值
void update(int l, int r, int i, int jobr, int val){
if(l == r){
t[i] = val;
return;
}
int mid = (l + r) / 2;
if(jobr <= mid){
update(l, mid, i<<1, jobr, val);
}else{
update(mid+1, r, i<<1|1, jobr, val);
}
t[i] = Math.max(t[i<<1], t[i<<1|1]);
}
//[l, r]表示当前的范围,i表示数组t存储[l,r]的最大值的下标
//[0, jobr]表示要查询的区域
public int query(int l, int r, int i, int jobr){
if( r <= jobr){
return t[i];
}
int mid = (l + r) / 2;
if(jobr <= mid)
return query(l, mid, i<<1, jobr);
else
return Math.max(t[i<<1],query(mid+1, r, i<<1|1, jobr));
}
public List<Boolean> getResults(int[][] queries) {
int m = 0;
for(int[] q : queries) m = Math.max(m, q[1]);
m++;
t = new int[m << 2];
TreeSet<Integer> set = new TreeSet<>();//求相邻的障碍物的位置
set.add(0);
set.add(m);
List<Boolean> ans = new ArrayList<>();
for(int[] q : queries){
int x = q[1];
int pre = set.floor(x-1);//求x前的障碍物
if(q[0] == 1){
int nxt = set.ceiling(x);//求x后的障碍物
set.add(x);
update(0, m, 1, x, x-pre);//更新[0,x]的最大可放置的物品大小
update(0, m, 1, nxt, nxt-x);//更新[0,nxt]的最大可放置的物品大小
}else{
int mx = Math.max(query(0, m, 1, pre), x - pre);//分成两段求最大值
ans.add(mx >= q[2]);
}
}
return ans;
}
}