基础算法面试题---异或运算II

前言

最近在leetcode发现两道异或相关的题目,觉得挺好的,拿出来分享一下。

异或满足的规律

公式还是要清楚的
1、归零率:a ^ a = 0(自己异或自己结果为0)
2、恒等率:a ^ 0 = a(与0异或结果不变)
3、交换律:a ^ b = b ^ a
4、结合律:a ^ b ^ c = a ^ (b ^ c )

第一题:解码异或后的数组(leetcode.1720)

在这里插入图片描述

难度:简单

题目中给出的encoded[i] 公式如下:

encoded[i] = arr[i] XOR arr[i + 1]

我们可以利用归零律、恒等率、结合律,让等号两边同时异或arr[i + 1],即得到:

encoded[i] XOR arr[i + 1] = arr[i] XOR arr[i + 1] XOR arr[i + 1],

又因为:arr[i + 1] XOR arr[i + 1] 等于 0,arr[i] XOR 0 等于 arr[i]

所以最终公式变为:

arr[i] = encoded[i] XOR arr[i + 1]

题目中恰好又告诉了我们arr[0]的值,所以最终我们便能计算出arr数组中每个位置的值。

解题代码

public class LC_1720 {
    public int[] decode(int[] encoded, int first) {
        int n = encoded.length + 1;
        int[] ans = new int[n];
        ans[0] = first;
        for (int i = 1; i < n; i++) {
            ans[i] = encoded[i - 1] ^ ans[i - 1];
        }
        return ans;
    }
}

第二题:解码异或后的排列(leetcode.1734)

在这里插入图片描述

难度:中等

很显然本题从 encoded[i] = perm[i] XOR perm[i + 1] 这个公式开始分析,与第一题给出的公式一样,区别在与不知道perm数组第一个下标的元素值是多少了,那我们猜想假设我们能得到第一个下标的值,那么这题就解决了。

我们再分析题目,给出的条件中,指出perm 是前 n 个正整数的排列,且 n 是个 奇数 。

假设n等于5,那么perm中的数字就是由,1-5组成,假设就是【1,2,3,4,5】,顺序不一定,但是值一定是这5个数字的排列组合。

再回到encoded[i] = perm[i] XOR perm[i + 1] 公式中,我们可以看出:

encoded[0] = perm[0] XOR perm[1]
encoded[1] = perm[1] XOR perm[2]

那么encoded数组中所有数的异或结果应该如下:

perm[0] XOR perm[1] XOR perm[1] XOR perm[2] XOR perm[2] XOR perm[3]。。。XOR perm[n-1] XOR perm[n]

如果这样一直下去最终encoded数组中所有数异或的结果实际上就等于

perm[0] XOR perm[n]

这看起来没什么用,那我们换一个方式,不妨我们每隔一位异或一下,也就是:

encoded[0] XOR encoded[2] XOR encoded[4]。。。

那么最终将会得到:

perm[0] XOR perm[1] XOR perm[2] XOR perm[3] XOR perm[4] XOR perm[5]

也就得到了perm数组每一位异或后的结果。

现在我们再回到,perm 是前 n 个正整数的排列,这个条件中,上面已经说过了,perm下标1-5实际上就是数字1-5,只不过不一定数字和下标不一定是按照顺序对应而已,但是这并对于结合律来说并没有影响,所以我们只要让1-5异或即可。

上半部分:perm[0] XOR perm[1] XOR perm[2] XOR perm[3] XOR perm[4] XOR perm[5]

XOR

下半部分:1 XOR 2 XOR 3 XOR 4 XOR 5

又因为 perm[1] XOR perm[2] XOR perm[3] XOR perm[4] XOR perm[5],就是对应这1到5的异或结果,所以最终上下异或后得到perm[0]。

好了,现在我们终于拿到了perm[0],接下来按照第一题的方法即可。

代码

class Solution {
    public int[] decode(int[] encoded) {
        int[] ans = new int[encoded.length + 1];
        int n = encoded.length + 1;
        int a = 0;
        for (int i = 1; i <= n; i++) {
            a ^= i;
        }
        int e = 0;
        for (int i = 1; i < encoded.length; i += 2) {
            e ^= encoded[i];
        }
        ans[0] = a ^ e;
        for (int i = 0; i < encoded.length; i++) {
            ans[i + 1] = ans[i] ^ encoded[i];
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值