【算法详解】力扣136.只出现一次的数字

一、题目描述

力扣链接:力扣136.只出现一次的数字

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

输入:nums = [2,2,1]
输出:1

二、C++题解

2.1 哈希表方法

获取所有元素的哈希表,然后判断出现次数为1的那个即可。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> countMap;

        for (auto num : nums) {
            ++countMap[num];
        }

        int target = 0;
        for(auto& entry : countMap) {
            if (entry.second == 1) {
                target = entry.first;
                break;
            }
        }
        return target;
    }
};

2.2 位运算(异或)

异或运算的两条性质:

  • 一个数和它本身做异或运算结果为 0,即 a ^ a = 0
  • 一个数和 0 做异或运算的结果为它本身,即 a ^ 0 = a

因此,将0与nums中所有元素进行异或运算,最后得到的结果便是只出现一次的数字。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;

        for (auto num : nums) result ^= num;

        return result;
    }
};

三、扩展阅读——位运算

  • 与运算(AND):对两个对应位进行比较,当两个对应位都为1时,结果为1;否则,结果为0。符号为 &

任何数和0做与运算,结果都是0,即 x & 0 = 0。例如,5(101) & 0 = 0。
任何数和其自身做与运算,结果是自身,即 x & x = x。例如,5(101) & 5(101) = 5(101)。

  • 或运算(OR):对两个对应位进行比较,当两个对应位中至少有一个是1时,结果为1;否则,结果为0。符号为 |

任何数和0做或运算,结果是自身,即 x | 0 = x。例如,5(101) | 0 = 5(101)。
任何数和其自身做或运算,结果是自身,即 x | x = x。例如,5(101) | 5(101) = 5(101)。

  • 异或运算(XOR):当两个对应位的值不同时,异或运算的结果为1;当两个对应位的值相同时,异或运算的结果为0。符号为^

任何数和0做异或运算,结果是自身,即 x ^ 0 = x。例如,5(101) ^ 0 = 5(101)。
任何数和其自身做异或运算,结果是0,即 x ^ x = 0。例如,5(101) ^ 5(101) = 0。
异或运算满足交换律和结合律,即 a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c。例如,5(101) ^ 3(011) ^ 4(100) = 5 ^ (3 ^ 4) = (5 ^ 3) ^ 4。

  • 非运算(NOT):对一个二进制数的每一位进行取反,将0变为1,将1变为0。符号为 ~

非运算会反转操作数的所有位。例如,~5(101) = 2(010)。

  • 左移运算(SHL):将一个二进制数的所有位向左移动指定的位数。左移操作会在二进制数的右侧补充相应数量的零。符号为 <<

左移n位等于乘以2的n次方,即 x << n = x * 2^n。例如,5(101) << 2 = 20(10100)。
左移运算不改变操作数的符号位。

  • 逻辑右移运算(SHR):将一个二进制数的所有位向右移动指定的位数。逻辑右移操作会在二进制数的左侧补充相应数量的零。符号为 >>

右移n位等于除以2的n次方,即 x >> n = x / 2^n。例如,20(10100) >> 2 = 5(101)。
逻辑右移运算会用0填充移位后产生的空位。

  • 算术右移运算(SAR):将一个二进制数的所有位向右移动指定的位数,但保持最高位(符号位)不变。算数右移操作会在二进制数的左侧补充相应数量的最高位(符号位)的值。符号为 >>>

算术右移运算会用符号位填充移位后产生的空位,因此它可以保持负数的符号。例如,对于负数-5(1011) >>> 2 = -2(1110)。

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