LeetCode初级算法之数组:136 只出现一次的元素

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

说明:

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

示例 1:

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

 

示例 2:

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

 

题目信息

输入:整数数组(只有一个数单个,其他数全部是两次的数组)

输出:整数(那个单个的数)

额外:时间复杂度O(n),空间复杂度O(1)

思考

一开始看漏了信息以为只有数组里只有一个不重复其他都是重复不限次数,忽略了重复只有2次。所以想到的只有万能的map计数,无论是找出现次数最多的还是出现一次的啥都可以。但并不满足空间复杂度,为了满足空间复杂度不使用额外记录那就是暴力扫描n^2,说到扫描就还对应一个更优的方式就是排序后再扫描nlogn但这两种也都不满足线性的时间复杂度。(记得上一篇判断数组是否有重复也有这几种思路使用容器或者双指针扫描)

//方式一:Map计数
public int singleNumber(int[] nums) {
    //定义map存<数字i,计数count>
    Map<Integer, Integer> map = new HashMap<>();
    for (Integer i : nums) {
        //如果之前存在计数则加一否则计为第一个
        Integer count = map.get(i);
        count = count == null ? 1 : ++count;
        map.put(i, count);
    }
    //计数统计结束,遍历所有key找到对应计数是1的
    for (Integer i : map.keySet()) {
        Integer count = map.get(i);
        if (count == 1) {
            return i;
        }
    }
    return -1;
}

 

//方式二:扫描比较
public int singleNumber(int[] nums) {
    //排好序、定义两个指针
    Arrays.sort(nums);
    int start = 0;
    int scan = 1;
    if(nums.length == 1){
        return nums[0];
    }
    /*
      当start不等于scan时
      scan停止移动
      并且比较差距判断是否出现一次
      或者scan停止的地方已经是最后一位
      否则继续把start移动到新数字上
    */
    while(start < nums.length){
        while(nums[start] == nums[scan]){
            scan++;
        }
        if(scan - start == 1){
            return nums[start];
        }else if(scan == nums.length -1){
            return nums[scan];
        }
        start = scan;
    }
    return -1;
}

以上两种方法都没有考虑条件中重复数字只是出现两次(输入数组有且只有一个数字唯一其他都是两次),解决的是其他重复数字重复多少都可以,并找到唯一的那个数。目前来说确实在数组中找到唯一数是不可能达到既满足不使用额外空间又满足线性时间复杂度。因此一定是在给出其他重复数字都是两次这样的条件下才可以实现。在这样的条件下有一种方式比上面计数就要优一点点两次相消虽然会使用额外空间但空间与时间比起计数都优化了一点

//方式三
public int singleNumber(int[] nums) {
    Set<Integer> set = new HashSet();
    for (Integer i : nums) {
        if(!set.add(i)){
            set.remove(i);
        }
    }
    return set.iterator().next();
}

但最终是要求是时间O(n),空间O(1)。那么只能是原地相消,扫描也不可能因为是时间O(nlogn)。只能遍历一遍并且记录到最后就只剩那一个,这个时候运算熟悉的就会想到使用异或,相同运算结果为0,累计消到最后就剩下单着的那一个

//方式四
public int singleNumber(int[] nums) {
    int len = 0;
    for (int i : nums) {
        len ^= i;
    }
    return len;
}

总结

这一道题很容易就能想到hash表或者扫描比较的解决方法,主要就是最后利用异或运算的方式实现原地相消和线性的时间复杂度

 

 

 

 

往期推荐

 

存在重复元素

旋转数组

买卖股票的最佳时机 II

删除排序数组中的重复项

 

本文分享自微信公众号 - IT那个小笔记(qq1839646816)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值