今日心情:生活在慢慢走上正轨,慢慢走总能达到想去的地方。
题目描述:
LeetCode 剑指 Offer 56 - I. 数组中数字出现的次数
一个整型数组
nums里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

解题代码:(满足题目对于时间和空间复杂度要求的解法:异或+位判断)
- class Solution {
-
- //使用 异或进位
-
- public int[] singleNumbers(int[] nums) {
-
- //获取划分两组的
- int th = 0;
- for(int num:nums){
- th ^= num;
- }
-
- //找到最低位进行划分
- // 1. 相同的划分到同一组
- // 2. 不同的划分到不同组
- int div = 1;
- while((th & div) == 0){
- div <<= 1;
- }
-
- int group1 = 0;
- int group2 = 0;
-
- for(int num: nums){
- if((num & div) != 0){
- group1 ^= num;
- }else{
- group2 ^= num;
- }
- }
- return new int[]{group1,group2};
- }
- }
解题代码:(自己首先拿到题的时候想的,但是不满足题目对于空间复杂度的要求:HashMap)
- class Solution {
-
- //使用 map 记录可以实现(但是不满足题目空间复杂度的要求)
-
- public int[] singleNumbers(int[] nums) {
-
- HashMap<Integer,Boolean> map= new HashMap<>();
- LinkedList<Integer> arr = new LinkedList<>();
-
- for(int num: nums){
- map.put(num,!map.containsKey(num));
- }
-
- for(int num:nums){
- if(map.get(num)){
- arr.add(num);
- }
- }
- int len = arr.size();
- int[] res = new int[len];
- for(int i=0;i<len;i++){
- res[i] = arr.get(i);
- }
- return res;
- }
- }
解题思路:
自己首先拿到题的时候想到就是用HashMap进行记录然后找没有重复的,满足时间复杂度O(n)但是不满足空间复杂度O(1)的要求。然后想不出来就直接看题解,看如何进行操作能否达到要求的空间复杂度,题解用的就是 位 操作的方法。所以看两个数相不相同 除了可以用==比较,也可以用异或进行比较,相同为0,不同为1。0 异或 任何数 为 该数本身。
题解方法:
(1)要找出这两个只出现一次的数字,如果数组全部进行异或,那么最后的异或结果就是那两个只出现一次的数字。所以这两个不同的数字的区别信息其实就在他们的异或结果之中,题解的方法很巧妙,使用的异或结果中的最低为1的位来将数组划分为不同的两个组,划分的要求是将相同的数划分在同一个组中,不同的数分别在两个组中,这样分别对两个组里的所有数进行异或操作,最后的结果就是要找的不同的数。
(2)首先对数组中所有的数进行异或,得到的异或结果就是两个不同数的异或结果,因为其他的数都有重复异或结果为0,0异或其他数的结果为该数的本身。
(3)获得异或结果之后,找最低位为1(div):div起始为1,找th的最低位,div 与 th 进行位与 如果为0 则进行左移,否则找到了th的最低位。
(4)通过 div 将数组划分为两个组分别进行异或,因为div 是 两个不同数字的异或结果所以 可以直接通过 div 区分 两个不同数组,如果div 与 num 进行 位与,结果为1 划分到 group1 进行异或,如果为 0 划分到 group2进行异或。因为相同数的位相同,所以通过div 可以直接划分到同一组中,div 本身就是用来区别不同数字的所以,不同数组会被分别划分到group1和group2。
(5)返回 group1 和 group2 的异或结果就是这两个不同数。