136.只出现一次数字的数组

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

说明:

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

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

输入: [4,1,2,1,2]
输出: 4
解法1 暴力破解
暴力破解的前提是你的数组是有序的,不是有序的,你遍历整个数组,你是无法进行比较的。在函数的开始,我就使用JS自带的sort排序进行排序(sort使用的是插入排序和快速排序结合的排序算法。数组长度不超过10时,使用插入排序。长度超过10使用快速排序。在数组较短时插入排序更有效率。)
遍历时候的时间复杂度是O(lgN)的。比较,就需要比较前面一个和后面一个。这样更加准确,只要二者都不相同,那么肯定就是它了(for里面是i+2的操作)
暴力肯定不是最优解,如果数组中有一万个变量呢,排序都是一个大问题。
var singleNumber = function(nums) {
let len = nums.length;
    nums = nums.sort((x, y) => x - y);
    
    
    if (nums[0] != nums[1]) return nums[0];
    if (nums[len - 1] != nums[len - 2]) return nums[len - 1];
    for (let i = 2; i < len - 2; i += 2) {
        if (nums[i] != nums[i - 1] && nums[i] != nums[i + 1]) return nums[i];}
    }
解法2 去重法 利用JS的Set方法
这个思路就很简单,如果不存在就往里面放该数值,如果再次出现就删除!有限制—重复的元素必须是出现二次,不能是奇数次(3次的话,不存在添加,存在删除,不存在添加)就会有大问题。最后Set里面只会剩下一个值,那个就是没有重复的数值。说实话,Set取值(不知道数值的前提)是真的麻烦。如果能像数组那样,按照索引就好了。这里只好借助里面自带的循环,把数值取出来。
var singleNumber = function(nums) {
    let hasObj = new Set()
    for (item of nums) {
        if (hasObj.has(item)) {
            hasObj.delete(item)
        } else {
            hasObj.add(item)
        }
    }
    let a
    hasObj.forEach(function(item) {
        a = item
    });
    return a
};
let nums = [1, 1, 2, 2, 3, 3, 4]
let a = singleNumber(nums)
console.log(a)
解法3 求差法
思路:先对数组排序,显而易见的,单独出现一次的数据必然是出现在数组下标为偶数的位置(下标从0开始),那么所有奇数下标的元素之和减去偶数下标的元素之和,就是需要求得的结果。
var singleNumber = function(nums) {
    nums.sort()
    let sum = 0
    for (let i = 0; i < nums.length; i++) {
        sum = i % 2 == 0 ? sum + nums[i] : sum - nums[i]
    }
    return sum
};
解法4 异或法
根据异或运算的特点,相同的数字经过异或运算后结果为0,除单独出现一次的数字外,其他数字都是出现两次的,那么这些数字经过异或运算后结果一定是0。而任何数字与0进行异或运算都是该数字本身。所以对数组所有元素进行异或运算,运算结果就是题目的答案。
其实严格来讲,只有第四种方式是题目想要的解法,其他三种方法都是有瑕疵的。也只有最后一种,时间复杂度是O(n)空间复杂度O(1)的。其他的二种有排序,时间复杂度不小,还一样Set需要额外的空间。
列子: 1, 4, 2, 3, 2, 4, 1对他们进行异或
最开始0的二级制表示为0000 0000,1的二进制表示为0000 0001
0000 0000 ^ 0000 0001 = 0000 0001//0和[1]进行异或获得的二进制转换成十进制就是1咯,把得到的1继续异或下面的数组
0000 0001 ^ 0000 0100 = 0000 0101//1和[4]进行异或得到十进制数字是5,十进制没什么用了,我就不写了,继续异或
0000 0101 ^ 0000 0010 = 0000 0111//
0000 0111 ^ 0000 0011 = 0000 0100//
0000 0100 ^ 0000 0010 = 0000 0110//
0000 0110 ^ 0000 0100 = 0000 0010//
0000 0010 ^ 0000 0001 = 0000 0011//最后就得到3了
--------------------- 
var singleNumber = function(nums) {

    let sum = 0
    for (let i = 0; i < nums.length; i++) {
        sum = sum ^ nums[i]
    }
    return sum
};
对于最后一种方法,建议大家再去了解一下JS那些位运算。虽然数学上可能用的多,JS上并没有大幅文字来讲解,但不代表它不重要。既然出现,就一定有使用它们的机会。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值