美团笔试2020.4.02第五题max xor min

美团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: 刚刚理解单调栈,代码写得太垃圾了,感觉有很多冗余代码,有没有兄弟帮我修改一下

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值