算法 - 神奇的异或

什么是异或?

同0异1。在java内就是X^Y

  • 任何数异或0为任何数 0 ^ n = n
  • 任何数异或1,n为奇数,n^ 1 = n-1;n为偶数 n^1=n+1
  • 相同的数异或为0: n ^ n = 0
  • a^ b=c a ^b ^d = c ^d 满足结合律

使用经验

1.数组中的单一元素

给你一个仅由整数数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。

1 <= nums.length <= 10^5
来自力扣

解法其实很简单,相同的数为0,不同的数为1

class Solution {
    public int singleNonDuplicate(int[] nums) {
        int ans = nums[0];
        for(int i=1; i<nums.length-1;i++){
            ans = ans^x;
        }
        return ans;
    }
}

2.数组中的单一元素(进阶)

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

来源

 public int singleNumber(int[] nums) {
        int a = 0, b = 0;
        for (int num : nums) {
            b = ~a & (b ^ num);
            a = ~b & (a ^ num);
        }
        return b;
    }

3.有序数组中的单一元素

给你一个仅由整数有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。

由于数组是有序的,因此数组中相同的元素一定相邻。对于下标 x 左边的下标 y,如果nums[y]=nums[y+1],则 y一定是偶数;对于下标x 右边的下标 zz,如果nums[z]=nums[z+1],则 z 一定是奇数。由于下标 x 是相同元素的开始下标的奇偶性的分界,因此可以使用二分查找的方法寻找下标 x。

利用按位异或的性质,可以得到mid 和相邻的数之间的如下关系,其中⊕ 是按位异或运算符:

当 mid 是偶数时,mid+ 1 =mid⊕1;

当mid 是奇数时,mid - 1 =mid⊕1。

如果上述比较相邻元素的结果是相等,则 mid<x,调整左边界,否则 mid≥x,调整右边界。调整边界之后继续二分查找,直到确定下标 xx 的值。
因此在二分查找的过程中,不需要判断mid 的奇偶性,mid 和mid⊕1 即为每次需要比较元素的两个下标。
在这里插入图片描述

 public int singleNonDuplicate(int[] nums) {
        if (nums.length == 1) return nums[0];
        int low = 0, high = nums.length - 1;
        while (low < high) {
            int mid = (low + high) / 2;
            if (nums[mid] == nums[mid ^ 1]) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return nums[low];
    }

4. 解码异或后的数组

未知 整数数组 arr 由 n 个非负整数组成。
经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] = arr[i] XOR arr[i + 1] 。例如,arr = [1,0,2,1] 经编码后得到 encoded = [1,2,3] 。
给你编码后的数组 encoded 和原数组 arr 的第一个元素 first(arr[0])。
请解码返回原数组 arr 。可以证明答案存在并且是唯一的。
示例 1:
输入:encoded = [1,2,3], first = 1
输出:[1,0,2,1]
解释:若 arr = [1,0,2,1] ,那么 first = 1 且 encoded = [1 XOR 0, 0 XOR 2, 2 XOR 1] = [1,2,3]
示例 2:
输入:encoded = [6,2,7,3], first = 4
输出:[4,2,0,7,4]
链接:https://leetcode-cn.com/problems/decode-xored-array

思路便是从自身异或自身为0出发与结合律。已知首个为first并且下一个与首个有异或关系,令fisrt异或自身,找等价关系。

    /**
     * encoded[i-1]= arr[i] ^ arr[i-1]
     * encoded[i-1]^encoded[i-1] = arr[i]^arr[i-1]^encoded[i-1]
     * encoded[i-1]^encoded[i-1] = 0
     * arr[i]^arr[i-1]^encoded[i-1] =0  由 a异或b = 0 =》a=b 推出 arr[i] = arr[i-1]^encoded[i-1]
     * arr[i]=arr[i-1]^encoded[i-1]
     *
     * @param encoded
     * @param first
     * @return
     */
    public int[] decode(int[] encoded, int first) {
        int[] arr = new int[encoded.length + 1];
        arr[0] = first;
        for (int i = 1; i < arr.length; i++) {
            arr[i] = arr[i - 1] ^ encoded[i - 1];
        }
        return arr;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值