解密「只出现一次的元素」:两种线性时间复杂度算法解析

156 阅读3分钟

引言

在计算机编程中,面对数组中只有一个元素出现一次,其他元素均出现两次的问题,我们面临着如何高效解决的挑战。本文将介绍两种基于不同思路的线性时间复杂度算法,用于解决这一问题,分别是基于排序和基于位运算的算法。

题目

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

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

方法一:基于排序的算法

思路解析

既然是只有一个数只出现一次 其他数字都是两次,我第一时间想到的是奇偶,因此也就想着是否有什么规律,于是就举例排列了一下:

image.png 如果我们将绿色矩形看作是那个唯一数 从上面简图可以发现(排序后):

数组的长度一定是奇数

唯一数一定排在奇数位

而且再多思考 就会发现 如果该奇数位不等于他后面的数 那么他一定就是唯一数了

算法步骤

  1. 对输入数组进行排序。
  2. 遍历排序后的数组,检查每一个元素是否和后面的元素相同,若不同,则当前元素即为唯一出现一次的元素。
  3. 如果遍历完数组仍未找到唯一的元素,说明最后一个元素是唯一的。

代码实现

时间复杂度为 O(nlogn),空间复杂度为O(n);

var singleNumber = function(nums) {
    nums.sort((a, b) => a - b);
    for (let i = 0; i < nums.length - 1; i += 2) {
        if (nums[i] !== nums[i + 1]) return nums[i];
    }
    return nums[nums.length - 1]; // 如果没有找到,则最后一个元素是唯一的
};

方法二:基于位运算的算法

异或操作有以下性质:

  • 任何数和 0 做异或运算,结果仍然是原来的数,即 a ^ 0 = a。
  • 任何数和其自身做异或运算,结果是 0,即 a ^ a = 0。
  • 异或运算满足交换律和结合律,即 a ^ b ^ a = (a ^ a) ^ b = 0 ^ b = b。

思路解析

我们知道了异或操作的特性,就可以利用异或运算找出只出现一次的元素。

算法步骤

  1. 遍历数组,对所有元素进行异或运算。
  2. 最终的结果即为唯一出现一次的元素。

代码实现

时间复杂度为 O(n),空间复杂度为 O(1)。

var singleNumber = function(nums) {
    let result = 0;
    for (let num of nums) {
        result ^= num;
    }
    return result;
};

总结

看见一些前辈说 如果第一想法不是用异或的思路,那么就是算法有所欠缺了,很惭愧,鄙人刚看见题目还是不能想到异或操作的思路,可见算法还是太少了,持之以恒或许才能找到算法的感觉吧 加油