剑指offer(C++)-JZ56:数组中只出现一次的两个数字(算法-位运算)

简介: 剑指offer(C++)-JZ56:数组中只出现一次的两个数字(算法-位运算)

题目描述:

一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

数据范围:数组长度2≤n≤1000,数组中每个数的大小0<val≤1000000

要求:空间复杂度O(1),时间复杂度O(n)

提示:输出时按非降序排列。

示例:

输入:

[1,4,1,6]


返回值:

[4,6]


说明:

返回的结果中较小的数排在前面  

解题思路:

本题考察位运算。两种解题思路。


1)暴力法


      使用哈希表记录出现频率,将频率为1的数输出即可。该方法的空间复杂度不符合题目要求。


2)异或运算


      异或运算指两个数相同为0,不相同为1。因为除了要寻找的数字出现了一次,其他数字都出现了两次,所以将这些数字进行异或运算后,根据其特性,重复出现的数字抵消了,只保留了出现了一次的数字。


      如4^1^2^1^2。4为100,1为001,2为010,4^1得到101,再^2得到111,再^1得到110,再^2得到100,即4。


      那如果有两个出现了一次的数字,则结果就相当于这两个数字异或。如4^1^2^1^2^3,最终的结果就是111,即4^3。


      本题目要求输出这两个数字,那如何将111拆开呢?4和3,如果某一位不相同,则异或结果该位就是1,我们定义t从001开始,将t与111与运算,寻找哪一位首次出现了1;111中最右即为1,说明在00x的位置,数字4和3是不一样的;再次遍历,将所有数据根据该位的数字分类,这样就能得到两个组,数字为1的组结果就是3,数字为0的组结果就是4。


      不得不说,这题目就是为这个解法量身定做的。。。各个条件完美匹配emm

测试代码:

1)暴力法

class Solution {
public:
    // 寻找出现一次的数字
    vector<int> FindNumsAppearOnce(vector<int>& nums) {
        unordered_map<int,int> um;
        vector<int> result;
        // 遍历数组
        int size = int(nums.size());
        for(int i = 0; i < size; ++i){
            um[nums[i]]++;
        }
        // 寻找出现频率为1的数
        for(int i = 0; i < size; ++i){{
            if(um[nums[i]] == 1){
                result.emplace_back(nums[i]);
            }
        }}
        // 按大小顺序输出
        if(result[0] < result[1]){
            return result;
        }
        else{
            return { result[1], result[0] };
        }
    }
};

2)异或运算

class Solution {
public:
    // 寻找出现一次的数字
    vector<int> FindNumsAppearOnce(vector<int>& nums) {
        vector<int> result{ 0, 0};
        // 遍历数组进行异或运算
        int temp = 0;
        int size = int(nums.size());
        for(int i = 0; i < size; ++i){
            temp ^= nums[i];
        }
        // 找到两个数不相同的第一位
        int t = 1;
        while((t & temp) == 0){
            t <<= 1;
        }
        // 再次遍历,将t位为1的数归为1组,为0的数归为1组,这样两组的异或运算得到的结果就是两个不重复数
        for(int i = 0; i < size; ++i){
            if((t & nums[i]) == 0){
                result[0] ^= nums[i];
            }
            else{
                result[1] ^= nums[i];
            }
        }
        // 按大小顺序输出
        if(result[0] < result[1]){
            return result;
        }
        else{
            return { result[1], result[0] };
        }
    }
};


相关文章
|
16天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
27 1
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
43 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
2月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
619 0
高精度算法(加、减、乘、除,使用c++实现)
|
2月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
26 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
2月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
36 0
|
2月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
2月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
2月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)
|
2月前
|
人工智能 算法 BI
一篇带你速通差分算法(C/C++)
一篇带你速通差分算法(C/C++)