136.Single Number

136.只出现一次的数字

题目描述

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

说明:

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

示例 1:

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

示例 2:

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

题解

对于问题中出现重复字眼的问题,我们都可以优先考虑使用hash方法进行求解,这不一定是最优的方法,但一般都可以得到正确的解。

  • 输出只出现一次的元素,不需要存储位置、次数之类的信息 使用hashset即可
  • 问题考虑,除了目标字符一次,其余字符都出现了2次,那么我们对字符进行add,remove操作,最后剩下的就是只出现一次的字符

对于该问题,要求不使用额外的空间进行实现,就需要使用一类新的方法了,位运算
异或运算的一些性质
相同位为0,不同位为1

  • 任何数与0异或都是它本身 3^0 = 011 ^ 000 = 011
  • 任何数与本身异或都是0 3 ^3 = 011 ^ 011 = 000
  • 因此我们可以对所有的元素进行异或,剩下的就是单个的元素本身了

代码

hashset:

class Solution {
    public int singleNumber(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        for(int num :nums){
            if(!set.contains(num)){
                set.add(num);
            }else{
                set.remove(num);
            }
        }
    return set.iterator().next();
    }
}

异或运算:

class Solution {
    public int singleNumber(int[] nums) {
        int single= 0;
        for(int num :nums){
                single ^= num;
        }
        return single;
    }
}

260.只出现一次的数字3

问题描述

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]
输出:[-1,0]

示例 3:

输入:nums = [0,1]
输出:[1,0]

题解

还是从hash表和位运算两个方面考虑
对于hash表方法,由于出现了两个出现一次的数

  • 使用hashmap保存每个字符出现的次数,保存下来
  • 对出现次数为一的进行输出 用到了Entry读取map的值

位运算的方法:

  • 考虑第一个问题,我们还是想要得到只出现一次的那个,那我们就需要把原数组分成两个部分,每个部分只有一个出现一次的元素且相同的两个元素要分到一个组!
  • 这样问题就转化为了第一题
  • 怎么实现呢?
  • 首先对所有的元素进行异或,这样得到

代码

hashmap:

    public int[] singleNumber(int[] nums) {
        Map<Integer,Integer> hashmap = new HashMap<Integer,Integer>();
        for(int num :nums){
            hashmap.put(num,hashmap.getOrDefault(num,0)+1);
        }

        int[] ret = new int[2];
        int index = 0;
        for(Map.Entry<Integer,Integer> entry : hashmap.entrySet()){
            int key = entry.getKey();
            int value = entry.getValue();
            if(value == 1){
                ret[index++] = key;
            }
        } 
        return ret;
    }

位运算

    public int[] singleNumber(int[] nums) {
        int ret = 0;
        // 对原组求异或结果为 a^b
        for (int n : nums) {
            ret ^= n;
        }
        // 求异或数 最后一位不为0的数 作为划分数组依据
        int div = 1;
        while ((div & ret) == 0) {
            div <<= 1;
        }
        // 得到两个数a,b
        int a = 0, b = 0;
        for (int n : nums) {
            if ((div & n) != 0) {
                a ^= n;
            } else {
                b ^= n;
            }
        }
        return new int[]{a, b};
    }


137. 只出现一次的数字 II

题目描述

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

示例 1:

输入:nums = [2,2,3,2]
输出:3

示例 2:

输入:nums = [0,1,0,1,0,1,99]
输出:99

 

提示:

    1 <= nums.length <= 3 * 104
    -231 <= nums[i] <= 231 - 1
    nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次

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

题解

可以观察到这道题和上面两道题目的变化,除了单个元素外,其他的元素也出现了单数次数,因此:

  • 不能利用位运算 a^a = 0 的性质

那么我们还是先讨论hash方法 ,很明显,哈希表方法依然适用,我们只需要遍历记录每个字符出现的次数于hash表,然后输出次数唯一的那些元素即可。(不再赘述)

那么位运算的方法呢?

  • 已知除了目标元素,其余元素均出现了3次
  • 这意味着单看某一个二进制位的话,非目标元素都是3的倍数
  • 我们把所有元素的第i位求和,然后除以3,余数为目标元素的第i位

代码

hash:

    public int singleNumber(int[] nums) {
        Map<Integer, Integer> freq = new HashMap<Integer, Integer>();
        for (int num : nums) {
            freq.put(num, freq.getOrDefault(num, 0) + 1);
        }
        int ans = 0;
        for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
            int num = entry.getKey(), occ = entry.getValue();
            if (occ == 1) {
                ans = num;
                break;
            }
        }
        return ans;
    }

位运算:

    public int singleNumber(int[] nums) {
        int ans = 0;
        for (int i = 0; i < 32; ++i) {
            int total = 0;
            for (int num: nums) {
                total += ((num >> i) & 1);
            }
            if (total % 3 != 0) {
                ans |= (1 << i);
            }
        }
        return ans;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值