力扣剑指Offer 第22天 位运算(中等)剑指 Offer 56 - I. 数组中数字出现的次数剑指 Offer 56 - II. 数组中数字出现的次数 II

力扣剑指Offer 第22天 位运算(中等)剑指 Offer 56 - I. 数组中数字出现的次数剑指 Offer 56 - II. 数组中数字出现的次数 II

剑指 Offer 56 - I. 数组中数字出现的次数

题目

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:

2 <= nums.length <= 10000

题解

异或的性质

异或运算的几个性质

  • 交换律
  • 结合律(即(a XOR b) XOR c == a XOR (b XOR c))
  • 对于任何数x,都有x XOR x = 0,x XOR 0 = x
  • 自反性 A XOR B XOR B = A xor 0 = A —> A XOR B = C 则 C XOR B = A

通过lowbit方法获取一个数的最小1所在位置

  • lowbit = x & (-x)
  1. 由自反性可以将数组所有数进行 异或 运算,去除所有2次出现的值,留下 c=a^b (a!=b)
  2. 获取c最小1所在位置lowbit=c&(-c)(即ab最小的不同位,可以用任意不同位置区分,lowbit较为方便)
  3. nums数组中nums[i]&lowbit!=0(lowbit位存在1的num)进行 异或 运算(过滤2次出现的值与ab中没有该位1的值),得到d=a(或d=b)
  4. 那么ab的值在c^dd
class Solution {
    public int[] singleNumbers(int[] nums) {
        int c=0;//c=a^b [(a!=b)a,b是我们需要寻找的只出现一次的数]
        for(int i:nums)c^=i;
        int lowbit=c&(-c),d=0;//lowbit:a与b最小不同位 d:a或b
        for(int i:nums)if((i&lowbit)!=0)d^=i;
        return new int[]{d,c^d};
    }
}

剑指 Offer 56 - II. 数组中数字出现的次数 II

题目

在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1
限制:

1 <= nums.length <= 10000

1 <= nums[i] < 2^31

题解

位运算

对每一位的1进行计数,如果能被3除则说明该为为0,否则为1

使用tflag进行当前各个位1数量状态记录

个数 t flag
0 0 0
1 1 0
2 0 1

这里有一种情况没有使用 t=1 flag=1因为只需要记录三个状态,所以当t=1 flag=1时将其修改为t=0 flag=0即可

class Solution {
    public int singleNumber(int[] nums) {
        int flag=0,t=0,tmp=0;
        for(int i:nums){
            //更新状态
            flag^=t&i;
            t^=i;
            //将1 1(3个)状态设置为 0 0(0个)
            tmp=t&flag;
            t^=tmp;
            flag^=tmp;
        }
        return t;
    }
}

你可能感兴趣的:(leetcode,leetcode,算法,职场和发展)