leetcode:260. 只出现一次的数字 III

题目来源

题目描述

在这里插入图片描述

题目解析

位运算

如果直接异或运算的话,得到的数则为两个目标数的异或值,那应该怎么区分出这两个值呢?

我们试想一下,如果我们先将元素分成两组,然后每组包含一个目标值,那么异或之后,每组得到一个目标值,就可以将两个目标值分别求出了。比如:

  • 例: **a,b,a,b,c,d,e,f,e,f ** 分组后
  • A组:a, a , b, b, c 异或得到 c
  • B组:e, e, f, f, d 异或得到 d

那我们应该依据什么规则将其进行分类呢?

  • c、d是两个不同的数,那么二进制位上一定会有一位是不同的,那么我们就可以根据这一位(分组位)来将 c , d 分到两个组中,数组中的其他元素,要么在 A 组中,要么在 B 组中。

那我们应该怎么得到分组位呢?

  • 我们让c、d异或即可,异或运算就是对应位不同时得 1 ,异或之后值为 1 的其中一位则为我们分组。
  • 例 001 ⊕ 100 = 101,我们可以用最右边的 1 或最左边的 1 做为分组位,数组元素中,如果我们将最右边的1作为我们的分组位,最后一位为0则进入A组,为1则进入 B 组。

那么我们应该怎么借助分组位进行分组呢?

  • 我们处理c、d的异或值,可以仅仅保留异或值的分组位,其余位变为0,比如101 变成 001或 100
  • 为什么要这么做呢?我们可以根据 a & 1 来判断 a 的最后一位为 0 还是为 1,所以我们将 101 变成 001 之后,然后数组内的元素 x & 001 即可对 x 进行分组 。同样也可以 x & 100 进行分组.

那么我们如何才能仅保留分组位,其余位变为 0 呢?例 101 变为 001

我们可以利用 x & (-x) 来保留最右边的 1

在这里插入图片描述

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        // 一对相同的数字异或为0
        // 所以target为两个只出现了一次的元素的异或
        int xorsum = 0;
        for(auto num : nums){
            xorsum ^= num;
        }
        // 因为两数不同,lowbit必然不为0
        // 物理意义就是两个不同的数字不同的最低的位在哪
        int lowbit = xorsum == INT_MIN ? xorsum : xorsum & (-xorsum);

        int a1 = 0;
        int a2 = 0;

        // 重复上述的过程,但是将nums按照lowbit为1或者为0分类
        // 则两个数必然被分到不同的类目;而相同的数字一定在同一个类目
        // 所以按类目分别异或就可以得到两个不同的数字
        for(auto n : nums){
            if(n & lowbit){
                a1 ^= n;
            }else{
                a2 ^= n;
            }
        }
        
        return {a1, a2};
    }
};

在这里插入图片描述

类似题目

题目思路
leetcode:41. 无序数组中缺失的第一个正整数(数组数据范围[-oo, +oo]) First Missing Positive应该去垃圾区的情况:当前数 <= L ,当前数 > 右边界 ,出现了重复
leetcode:268. 无序数组缺失的那个数(数组数据范围在[0, n],数据长度为n) Missing Number如果我们补充一个完整的数组和原数组进行组合,那所求解的问题就变成了 只出现一次的数字。
leetcode:448. 无序数组缺失的那个数(数组数据范围在[1, n],数据长度为n) Find All Numbers Disappeared in an Array标记法:在原数组上进行一次遍历,在遍历的过程中,将遇到的元素所对应的index下的元素标记为负。最终哪些index下的元素没有被标记的则说明,这个index对应额元素没有出现过。置换法
leetcode:136. 无序数组出现一次的数字(出现一次的数字有一个,其他出现两次)Single Number异或相消,剩下来的就是想要的
leetcode:137. 无序数组出现一次的数字(出现一次的数字有一个,其他出现三次) II Single Number IISingle Number II对于出现三次的数字,各个二进制位出现的次数都是3的倍数。因此,统计所有数字的各二进制位中1的出现次数,并对3求余,结果则为只出现一次的数字(通用解法)。实现:对int的32个位每个位进行依次判断该位1的个数求余3后是否为1,如果为1说明结果该位二进制为1可以将结果加上去。最终得到的值即为答案。
leetcode:260. 无序数组出现一次的数字(出现一次的数字有两个,其余出现两次)Single Number III先将元素分成两组,然后每组包含一个目标值,那么异或之后,每组得到一个目标值。比如a,b,a,b,c,d,e,f,e,f,分组后;A组:a, a , b, b, c 异或得到 c;B组:e, e, f, f, d 异或得到 d
leetcode:287.无序数组出现多次的数字(一个数出现多次,其他数出现一次或者零次) (数组数据范围在[1, n],数据长度为n+1) Find the Duplicate Number因为不允许修改原数组,所以不能用标记法。而一般对于链表,数组中要求找重复的数字或者节点,都可以考虑用快慢指针的方法来解,也就是入环节点就是那个重复的数
leetcode:442.无序数组出现两次的整数(每个数出现一次或者两次,数组数据范围在[1, n])) Find All Duplicates in an Array标记法:对于每个nums[i],我们将其对应的nums[nums[i] - 1]取相反数,如果其已经是负数了,说明之前存在过,我们将其加入结果res中即可;置换法: 将nums[i]置换到其对应的位置nums[nums[i]-1]上去,最后在对应位置检验,如果nums[i]和i+1不等,那么我们将nums[i]存入结果res中即可
leetcode:645. 无序数组,有一个数字重复出现了一次,从而造成了另一个数字的缺失,请找出重复的数字和缺失的数字(数据范围在[1, n],数据长度为n) Set Mismatch 假设每个人各司其职, 那么每个岗位上就是相应的人员,并且各司其职, 但是现在混入了一个;闲杂人等, 他又害怕被人发现, 于是他就别人的岗位上站着, 结果等着等着, 这个岗位上应该来的人来了;他一看, 自己掩饰不过去了(毕竟人家不会跑到别的岗位上,抢别人的活干, 于是他就这么一直碰运气。 一直走到那个没来上岗的那个人的岗位上去, 这样谁都不会发现他是的闲杂人等.而且每个岗位上都满员了.
leetcode:142. 环形链表 II
leetcode:540. 有序数组中的单一元素(其他出现两次)二分
leetcode:389. 字符t比字符s多出的那个数 Find the Difference 异或
765. 情侣牵手Couples Holding Hands
565. 数组嵌套 Array Nesting
1207. 独一无二的出现次数先统计数字出现的频率,然后看相同频率是否重复出现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值