LeetCode136、 只出现一次的数字

68 阅读2分钟

LeetCode 系列记录我学习算法的过程。

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情

题目

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

说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例:

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


输入: [4,1,2,1,2]
输出: 4

思路

这个题目看起来很简单,只需要找到只出现过一次的数字即可

那我们可以遍历整个数组,然后将每个数字出现的次数记录下来,找到次数为 1 的即可:

  • 首先定义 map 存储所有数字及出现的次数
  • 遍历传入的数组
  • 当遍历项在 map 中有记录时,将次数加 1
  • 无记录则设置次数为 1
  • 最后遍历 map,将出现次数为 1 的数字返回即可

代码实现

/**
 * @param {number[]} nums
 * @return {number}
 */
var singleNumber = function(nums) {
    // 存储所有数字出现的次数
    const map = new Map()
    // 遍历传入的数组
    nums.forEach(n => {
        // 如果有记录,则将其出现次数加 1
        if (map.has(n)) {
            map.set(n, map.get(n) + 1)
        } else {
        // 无记录则设置次数为 1
            map.set(n, 1)
        }
    })
    // 遍历所有记录
    for(let [key, value] of map) {
        // 如果当前遍历项值为1,返回key
        if(value === 1) return key
    }
};

image.png

优化

没仔细审题,题目还有一个提示就是除了只出现一次的数字,其他数字都只出现两次,这个其实是一个很好的切入点,可以用到位运算中的异或( ^ )

异或( ^ )

  • 一个数和 0 做 异或 运算等于本身
  • 一个数和其本身做 异或 运算等于 0

故而在以上的基础条件上,将所有数字按照顺序做异或运算,最后剩下的结果即为只出现一次的数字

这样实现下来的话 时间复杂度:O(n),空间复杂度:O(1):

var singleNumber = function(nums) {
    // 存储最后的答案
    let ans = 0
    // 遍历传入的数字
    for(const num of nums) {
        // 进行 异或 操作
        ans ^= num
    }
    // 返回结果
    return ans
};

image.png