0
点赞
收藏
分享

微信扫一扫

力扣热门100题——只出现一次的数字

大自然在召唤 2022-03-27 阅读 96

10、只出现一次的数字

1.问题描述

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

说明:

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

2.示例

示例 1:

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

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

3.具体解法(哈希表,集合,求和方法,位运算——异或)

//方法一:自己想的遍历法,但是想错了,写成了找出重复的数字,不过过程中锻炼了自己的思维,还强化了哈希表的创建过程
//对于哈希表的使用开始有思路了,但是这道题用哈希表可能有点浪费,但是为了用它的containsKey方法,所以我把键和值都存同样的
//其实这样感觉用一个数组或者链表就可以了,而我们是为了查询使用,所以应该是数组,但是数组有没有类似containsKey的方法,我不知道,所以只能用哈希表了
/*
class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer,Integer> hs=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(hs.containsKey(nums[i])){//如果哈希表里有当前遍历到的数字,就返回这个数字
                return nums[i];
            }
            else{
                hs.put(nums[i],nums[i]);//没有就存入哈希表
            }
        }
        return -1;//这里要求我必须有一个返回值,没办法写了return;,但是会报错,所以只能写了个返回-1
                  //为什么非要一个返回值呢,明明我在for循环那里已经写了返回值,原因应该是else不一定能执行到,虽然我们知道案例里肯定有
                  //所以对于这种情况的处理要有所掌握


    }
}

//随后我进行了思路的改进
//当哈希表中有这个元素的时候,就把这个元素移除,没有就存进去,这样的话,就可以最后只剩下一个没重复的元素在哈希表里
//但我取不出来,因为最后我试图找到一个方法返回哈希表的最后一个元素,但是没有,我试着return hs;会报错
//想到这个应该是哈希表的遍历的内容了,我可以遍历哈希表,最后返回就可以了,但哈希表的遍历我还没掌握
//水平到这里了,目前没法将这个代码成功实现,得换个东西来实现,能用哈希表了
class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer,Integer> hs=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(hs.containsKey(nums[i])){
                hs.remove(nums[i]);
            }
            else{
                hs.put(nums[i],nums[i]);
            }
        }
        return hs;
    }
}

//既然哈希表不可以,我想着用List集合来存储,而且Set集合也有contains(Object o)这样的判断方法
//但也是没找到返回这个值的方式,所以只能到这里了,以后有能力再改进

 */
//方法二:位运算
//如果不考虑时间复杂度和空间复杂度的限制,这道题有很多种解法,可能的解法有如下几种。
//1.使用集合存储数字。遍历数组中的每个数字,如果集合中没有该数字,则将该数字加入集合,
//如果集合中已经有该数字,则将该数字从集合中删除,最后剩下的数字就是只出现一次的数字。

//2.使用哈希表存储每个数字和该数字出现的次数。
//遍历数组即可得到每个数字出现的次数,并更新哈希表,最后遍历哈希表,得到只出现一次的数字。

//3.使用集合存储数组中出现的所有数字,并计算数组中的元素之和。
//由于集合保证元素无重复,因此计算集合中的所有元素之和的两倍,即为每个元素出现两次的情况下的元素之和。
//由于数组中只有一个元素出现一次,其余元素都出现两次,因此用集合中的元素之和的两倍减去数组中的元素之和,剩下的数就是数组中只出现一次的数字。

//可以发现,看了官方的解释,其思路与我的想法一致,但是呢比我的细节要优秀很多
//比如第一个想到用集合,第二个想到存储数字和字数,第三个用求和的形式

//上述三种解法都需要额外使用O(n)的空间,其中n是数组长度。
//如何才能做到线性时间复杂度和常数空间复杂度呢?
//答案是使用位运算。对于这道题,可使用异或运算⊕。

//任何数和0做异或运算,结果仍然是原来的数
//任何数和其自身做异或运算,结果是0
//异或运算满足交换律和结合律
//根据上面的三个性质可以发现,数组中的全部元素的异或运算结果即为数组中只出现一次的数字。
/*
class Solution {
    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }
}
 */

//附上一个使用哈希表成功的算法
/*
class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for (Integer i : nums) {
            Integer count = map.get(i);//获得数字这个值在哈希表中的键值对,也就是这个值对应的次数
            count = count == null ? 1 : ++count;//看次数是不是存在,也就是是不是存储过,没存过就记为1,存过就++
            map.put(i, count);
        }
        for (Integer i : map.keySet()) {
            Integer count = map.get(i);
            if (count == 1) {
                return i;//循环遍历哈希表,这个也正是我不会的哈希表遍历部分
                         //遍历键,找到值是1,的返回其键值;
            }
        }
        return -1; // can't find it.
    }
}

 */

4.收获

  • 对于必须有一个返回值,但是又不知道怎么去在最后面的位置去写一个return,我想到的是return -1;,以后应该会能学习到更好的处理方法
  • 对于哈希表的遍历还没掌握,List的遍历也没掌握
  • 这个题目如果是其他的都是未知次(不等于1),这个时候用哈希表是非常好的
  • 学会了位运算的思路,异或等位运算
  • “异或”用人话来说就是“找不同”,比如两幅图找不同,不同的点才为true,相同的部分为false。
举报

相关推荐

0 条评论