LeetCode-初级算法-只出现一次的数字

10 篇文章 0 订阅
10 篇文章 0 订阅

运行结果

在这里插入图片描述

一、题目

在这里插入图片描述

二、分析

1、 根据题目的介绍我们可以得到以下结论

  • 数组不为空,而且有一个元素至出现了1次,其余元素均出现了2次
  • 数组的长度为奇数,即数组长度为1 、3、5、7…( 2 * i + 1 ) …等
  • 线性时间复杂度:时间复杂度最高为O(n)
  • 不使用额外空间:空间复杂度最高为O(1)

方法一:
使用异或运算(^)

  • 异或运算是在数值的二进制码上进行的操作,对应位相同为0,不同为1
  • 两个相同的数字异或运算的结果为0
  • 0与任意数字异或运算的结果为该数字

①有了以上结论,我们可以将数组中的所有元素进行异或运算,得到的结果一定是单独出现的元素。
②使用for循环从数组第二位(即下标为1)的运算开始,每循环一次将该元素与nums[0]进行异或运算, 得到的结果再次赋给nums[0] ,即使用 ^= 运算符。
③此方法还有一个好处就是保证当数组长度为1时仍然能得到正确结果。

方法二:
该方法执行时间长,而且因为使用了Arrays.sort(int[ ] a)方法,分析源码可知此方法的时间复杂度是O(n^3),不符合题意,但是这种想法依然是一个非常好的想法。
奇数位元素与偶数位元素相减

① 在上面的结论中我们知道数组的长度为奇数即( nums.length = 2 * x +1 );而重复的元素出现的次数均为2次。
②我们试想一下,如果将数组中所有元素进行加减操作,若是相同的元素进行相减,其余进行相加操作,最后得到的结果是不是就是单独出现的元素呢?
③为了实现前面的想法,我们可以用Arrays的静态方法sort先对数组进行升序排列,排列之后相同的元素总是挨着的,例如对数组 [ 1,5,6,1,6 ]进行升序排列后得到的结果为 [ 1,1,5,6,6 ] 总共有5个元素,(注意以下所有的解释中使用的是位数而不是下标,第1位对应的下标 index = 0)对第1、3、5位元素求和,再对第2、4位元素求和,将两个和相减就会得到单独的元素的值
④因为数组长度是奇数,所以奇数位的个数和总是比偶数位的个数和多1,又因为对数组排序后相同元素是挨着的,这样就能保证相同的元素总是一个在奇数位一个在偶数位,所以两个和相减之后会把所有相同的元素都减去,剩下的那个就是单独出现的元素。
⑤在方法二中使用for循环,从第二位(下标index = 1)开始循环,使用三目运算符,如果是偶数位就与nums [0] 相减,如果是奇数位就与nums [0]相加,最后再赋给nums [0] ,直至循环完成。这样可以保证当数组长度为1时仍然能得到正确结果。

三、源码

方法一:

class Solution {
    public int singleNumber(int[] nums) {
        for(int i=1;i<nums.length;i++){
            nums[0] ^= nums[i];
        }
        return nums[0];
    }
}

方法二:

class Solution {
    public int singleNumber(int[] nums) {
        Arrays.sort(nums);
        for(int i = 1;i<nums.length;i++){
            nums[0] = (i % 2 == 0?nums[0] + nums[i] : nums[0] - nums[i]);
        }
        return nums[0];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值