美团2020.4.02笔试题 5: max xor min
题目描述
给你一个长度为n的序列a,请你求出对每一个1<=l<r<=n的区间中最大值和最小值的异或和的异或和。
例如序列为{1,3,5},不同的a(1,2)=1^3 ,a(1,3)=1^5 ,a(2,3)=(3^5), a(1,2) ^a(1,3) ^a(2,3)=0,所以最后的答案是0。
输入要求:
输入第一行仅包含一个正整数n,表示序列的长度。(1<=n<=10^5)
接下来一行有n个正整数a_i,表示序列a。(1<=a_i<=10^9)
输出要求:
输出仅包含一个整数表示所求的答案
例子:
输入:
3 1 3 5
输出:
0
import java.util.LinkedList;
import java.util.Scanner;
public class Test5 {
//最大值和最小值的异或和的异或和等价于最大值的异或与最小值的异或的异或
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for(int i = 0; i < n; i++){
nums[i] = sc.nextInt();
}
//维护一个单调增栈,从左向右遍历得到每个元素作为最小值的右边界,从右向左遍历得到每个元素作为最小值的左边界
//规则:遍历时,出栈时返回该次循环第一次出栈元素的下标,遍历完成后,出栈时返回遍历完成时刻栈顶元素的下标
LinkedList<Integer> stackInc = new LinkedList<>();
int[] Lmin = new int[n];
int[] Rmin = new int[n];
//维护一个单调减栈,从左向右遍历得到每个元素作为最大值的右边界,从右向左遍历得到每个元素作为最大值的左边界
//规则:遍历时,出栈时返回该次循环第一次出栈元素的下标,遍历完成后,出栈时返回遍历完成时刻栈顶元素的下标
LinkedList<Integer> stackDec = new LinkedList<>();
int[] Lmax = new int[n];
int[] Rmax = new int[n];
for(int i = 0; i < n; i++){
int curMin = 0;
if (!stackInc.isEmpty()) {
curMin = stackInc.peek();
}
while(!stackInc.isEmpty() && nums[i] < nums[stackInc.peek()]){
Rmin[stackInc.poll()] = curMin;
}
stackInc.push(i);
int curMax = 0;
if (!stackDec.isEmpty()) {
curMax = stackDec.peek();
}
while(!stackDec.isEmpty() && nums[i] > nums[stackDec.peek()]){
Rmax[stackDec.poll()] = curMax;
}
stackDec.push(i);
}
int topRmin = stackInc.peek();
while(!stackInc.isEmpty()){
Rmin[stackInc.pop()] = topRmin;
}
int topRmax = stackDec.peek();
while(!stackDec.isEmpty()){
Rmax[stackDec.pop()] = topRmax;
}
for(int i = n-1; i >= 0; i--){
int curMin = 0;
if (!stackInc.isEmpty()) {
curMin = stackInc.peek();
}
while(!stackInc.isEmpty() && nums[i] < nums[stackInc.peek()]){
Lmin[stackInc.poll()] = curMin;
}
stackInc.push(i);
int curMax = 0;
if (!stackDec.isEmpty()) {
curMax = stackDec.peek();
}
while(!stackDec.isEmpty() && nums[i] > nums[stackDec.peek()]){
Lmax[stackDec.poll()] = curMax;
}
stackDec.push(i);
}
int topLmin = stackInc.peek();
while(!stackInc.isEmpty()){
Lmin[stackInc.pop()] = topLmin;
}
int topLmax = stackDec.peek();
while(!stackDec.isEmpty()){
Lmax[stackDec.pop()] = topLmax;
}
int max = 0;
int min = 0;
//找到每个位置作为最大值或最小值时所在的区间个数,为奇数则可以异或
for(int i = 0; i < n; i++){
if(((i - Lmax[i] + 1) * (Rmax[i] - i + 1) - 1) % 2 == 1){
max ^= i;
}
if(((i - Lmin[i] + 1) * (Rmin[i] - i + 1) - 1) % 2 == 1){
min ^= i;
}
}
System.out.println(max ^ min);
}
}
ps: 刚刚理解单调栈,代码写得太垃圾了,感觉有很多冗余代码,有没有兄弟帮我修改一下