【practise】只出现一次的数字

简介: 【practise】只出现一次的数字

现在给你一个数组,里面放了一些数字,里面都是两两成对,只有一个数字是单独的,要求找出其中只出现一次的数字。相必这道题是非常简单了,有很多解法比如说用暴力求解?比如说用位运算?甚至说用哈希数组统计?

相信大家都有很多方法去解决这个简单的问题,在本文中我收录了三道比较简单的关于“只出现一次的数字”话题的三道题目,我均用位运算的方法去解决,有需要借鉴即可。

1.只出现一次的数字1

题目链接:LINK

class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        // 异或思路
        /*
        * 原理:
        * 两个相同的数字相异或为0
        * 0异或上任何数字都为任何数字
        * 异或支持交换律
        */
        int ret = 0;
        for(auto& n: nums)
        {
            ret^=n;
        }
        return ret;
    }
};

上面这道题非常简单,我不再多说。

接下来上一点点难度。

2.只出现一次的数字2

题目链接:LINK

看到这个题目是不是感觉直接位运算不行了?直接位运算的确不行,但是我们到比特位的视角仍然是可以滴。

这个题目之前是写过博客的,详细情况去直接看我写的那个博客文章吧:链接是LINK

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        // 以比特位为单位,对每个数据进行遍历
        for(int i = 0; i < 32; i++)
        {
            int count = 0;
            // 统计所有数字第i位有多少个1
            for(auto& n: nums)
            {
                if(((n >> i) & 1) == 1)
                {
                    count++;
                }
            }
            // 如果这个1的个数模3刚好剩下一个,那么我们的ret也是要有1的。
            if(count % 3 == 1)
            {
                ret = (ret | (1 << i)); 
            }
        }
        return ret;
    }
};

好,倘若你可以独立完成这道题,当然是第一次做的话,说明你的思维贼好使。我们继续来看下面这道题:

3.只出现一次的数字3

题目链接:LINK

这个思路就是把所有数字异或起来,最后得到一个数,这个数其实等价于恰好出现一次的那两个数相异或的结果。我们找到这个数有1的地方,说明两个要返回的数字对应位置的比特位是不一样的。然后我们再根据这个不一样的比特位让所有数分成两组,对每组单独异或就可得到两个要求的数字。

注:上图来源于力扣官方题解。

按照思路,我们可以写出下面代码:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        // 找出两个不同数的最右的差异为1
        int t_ret = 0;
        for(auto& n: nums)
        {
            t_ret^=n;
        }
        int l = t_ret & (-t_ret);
        // 根据差异我们将所有数字归为两类,一类是一位有1的,另一类是没1的。
        int ret1 = 0;
        int ret2 = 0;
        for(int& n : nums)
        {
            if(n & l)
            {
                ret1 ^= n;
            }
            else
            {
                ret2 ^= n;
            }
        }
        return {ret1, ret2};
    }
};

然后…

原因在于:

所以我们在分组之气做一个判断就行了:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        // 找出两个不同数的最右的差异为1
        int t_ret = 0;
        for(auto& n: nums)
        {
            t_ret^=n;
        }
        
        // 特殊情况:溢出问题,因为INT_MAX所表示的数字比INT_MIN少一个!此时取符号会溢出
        int l = (t_ret == INT_MIN ? t_ret : t_ret & (-t_ret));
        // 根据差异我们将所有数字归为两类,一类是一位有1的,另一类是没1的。
        int ret1 = 0;
        int ret2 = 0;
        for(int& n : nums)
        {
            if(n & l)
            {
                ret1 ^= n;
            }
            else
            {
                ret2 ^= n;
            }
        }
        return {ret1, ret2};
    }
};

4.总结

在上面三道题中我们都用了位运算的思路去做,第一道是比较常规的,第二道是需要理解比特位、位运算才可以想得到,第三道感觉是有点难度的,我就没想到…看的题解~


EOF

相关文章
|
10天前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
140 0
|
API 图形学 异构计算
Unity3D学习笔记7——GPU实例化(2)
Unity3D学习笔记7——GPU实例化(2)
111 2
|
关系型数据库 MySQL 数据库
EF Core反向工程
EF Core反向工程,数据库创建表使用命令生成上下文
163 0
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的七彩云南文化旅游网站附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的七彩云南文化旅游网站附带文章源码部署视频讲解等
167 16
|
数据可视化
Echarts高级进阶教程(3):appendData大数据量分片加载数据增量渲染和常规思路异步加载数据的对比,对折线图是无效的
Echarts高级进阶教程(3):appendData大数据量分片加载数据增量渲染和常规思路异步加载数据的对比,对折线图是无效的
815 0
|
JavaScript 前端开发
如何在 Angular 中使用响应式表单
如何在 Angular 中使用响应式表单
60 0
|
存储 缓存 Linux
实验 通过命令和代码初步感受存储管理【操作系统】
实验 通过命令和代码初步感受存储管理【操作系统】
256 0
|
存储 缓存 NoSQL
Springboot中使用redisson + 自定义注解优雅的实现消息的发布订阅
Springboot中使用redisson + 自定义注解优雅的实现消息的发布订阅
|
算法 Linux C++
linux中利用VScode编写python程序
linux中利用VScode编写python程序
linux中利用VScode编写python程序
|
调度 Android开发
自定义View之理解测量onMeasure和布局onLayout过程
自定义View之理解测量onMeasure和布局onLayout过程
143 0