剑指Offer 面试题40:数组中只出现一次的两个数 题解

面试题40:数组中只出现一次的两个数

提交网址:  http://www.nowcoder.com/practice/e02fdb54d7524710a7d664d082bb7811?tpId=13&tqId=11193

http://ac.jobdu.com/problem.php?pid=1351

题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

牛客网OJ的输入输出接口是:void FindNumsAppearOnce(vector<int> data,int* num1,int *num2),其中data是待查找的整型数组,而num1和num2是分别指向两个数的指针,返回值为*num1和*num2,要求原址进行,返回值为void类型。

输入:

每个测试案例包括两行:

第一行包含一个整数n,表示数组大小。2<=n <= 10^6。

第二行包含n个整数,表示数组元素,元素均为int。

输出:
对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。
九度OJ 样例输入:
8

2 4 3 6 3 2 5 5

样例输出:
4 6

分析:

按位异或^具有如下性质:

1. 任何一个数字异或它自身都等于0。

2. 异或满足恒等式(a^b)^b=a,这还可以用来作变量值的快速交换,虽然本题不需要作变量值的交换。

故用两次异或运算特点可以解决此问题:

(1) 先从头到尾依次异或原数组中的每一个数字,那么最终的结果刚好只出现一次的数字的异或结果,因为成对出现的两次的数字全部在异或中抵消了。

(2) 原数组中有两个数字只出现一次,且两个只出现一次的数肯定不相等,它们的异或结果一定不为0,一定有一个数在某位(记作倒数第k位)上有1,另外一个数的此位上没有1。因此我们想办法把原数组分成两个子数组,使得每个子数组包含一个只出现一次的数字,一个子数组的此位上一定有1,另个子数组的此位上一定没有1,然后分别对每个子数组求异或,因为划分后的两个子数组有这样的特点:其他数都出现两次,只有一个数只出现一次。因此,我们可以再次运用按位异或运算,分别得到两部分只出现一次的数。

AC代码:

#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2)  // 返回值的大小顺序没作要求,输入的数组也不一定是有序的
	{
		if(data.size()<2) return ;  // 返回值为void类型,出口应该这样写
		int partFlag=0x1;  // partFlag为两类数的划分标志,是可变的
		int xorRes=0;
		for(int i=0; i<data.size();i++)
			xorRes ^= data[i];
		*num1 = xorRes;
		*num2 = xorRes;
		while((xorRes & partFlag)==0)
			partFlag <<= 1;  // a & 0x1 等价于a%2,在这用来判断最后一位是0还是1,
                            // 找到xorRes中的1个位置时,partFlag的最高位(倒数第k位)是1,其他位全0
		for(int i=0; i<data.size();i++)
		{
			if((data[i] & partFlag)==0) *num1 ^= data[i]; // 判断data数组中所有数的倒数第k位是0还是1,*num1是两单次出现的数中的较大者
			else *num2 ^=data[i]; // *num1是两单次出现的数中的较大者, *num2是较小者
		}
    }
};
// 以下为测试
int main()
{
    vector<int> data1 = {3,1,10,1,3,6,2,6};
    int* num1 = new int;
    int* num2 = new int;
    Solution sol;
    sol.FindNumsAppearOnce(data1, num1, num2);
    cout<<*num1<<" "<<*num2<<endl;
    return 0;
}

此题有个简化版:

136. Single Number

提交网址:https://leetcode.com/problems/single-number/

Total Accepted: 127018 Total
Submissions: 255025 Difficulty: Medium

Given an array of integers, every element appears twice except for one. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

AC代码:

#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
    int singleNumber(vector<int>& nums)
    {
        if(nums.size()<1) return 0;
        int res, xorRes=0;
        for(int i=0; i<nums.size();i++)
            xorRes ^= nums[i];
        res = xorRes;
        return res;
    }
};

int main()
{
    vector<int> data1 = {3,1,10,1,3,6,6};
    Solution sol;
    int res1=sol.singleNumber(data1);
    cout<<res1<<endl;
    return 0;
}

相关链接: https://yq.aliyun.com/articles/3511

时间: 2024-09-29 10:59:29

剑指Offer 面试题40:数组中只出现一次的两个数 题解的相关文章

剑指offer 面试题40—数组中两个只出现一次的数字

题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度O(n),空间复杂度O(1). 基本思想: http://blog.csdn.net/wtyvhreal/article/details/44260321 #include <iostream> using namespace std; int Find1(int n)//从低位开始找第一个1的位置 { int index=0; while((n&1)==0 &&a

剑指offer系列源码-数组中只出现一次的数字

题目1351:数组中只出现一次的数字 时间限制:1 秒内存限制:32 兆特殊判题:否提交:2582解决:758 题目描述: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组大小.2<=n <= 10^6. 第二行包含n个整数,表示数组元素,元素均为int. 输出: 对应每个测试案例,输出数组中只出现一次的两个数.输出的数字从小到大的顺序. 样例输入: 8 2 4 3 6 3 2 5 5

剑指offer 面试题36—数组中的逆序对

题目: 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4) 基本思想: 解法一:O(n^2) 最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是O(n^2). 解法二:O(nlogn) 归并排序思路: 例如7,5,4,6可以划分为两段7,5和4,6两个子数组 1

【剑指offer】Q29:数组中出现次数超过一半的数字

就本题而言,个人觉得练习下partition函数是有必要的,毕竟它是快速排序的核心,是基础性的东西,也是必须要掌握的,至于书中给出的"取巧"性解法,是属于个人思维能力的考察,是一种考虑问题的思路,不是一两个问题就能练就的. partition函数,包括快速排序,是一定要信手拈来的,必须的. import random def MoreThanHalf(array): if len(array) == 0: return 0 start = 0 end = len(array) - 1

【剑指offer】二维数组中的查找

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 分析: 首先选择数组中右上角的数字.如果该数字等于要查找的数字,查找过程结束:如果该数字大于要查找的数字,剔除这个数字所在的列:如果该数字小于要查找的数字,剔除这个数字所在的行.依次类推,直到查找范围为空. 示例程序: #include <stdio.h> #include <stdlib.h> int

剑指OFFER之二维数组中的查找(九度OJ1384)

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数. 输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字. 接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每

【剑指offer】Q40:数组中出现一次的数字

按着书里面讲述的方法,根据某一位来将整个数组拆分成两个部分,取每一部分中出现一次的数.书中的处理略显复杂,这里简化下分类的方法. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return first, second def f

【剑指offer】Q40:数组中出现一次的数

书里面关于分类的判断有些麻烦,通过某一位为0为1来对数组元素进行分类.假如第3位为1,那么也就是元素x & 8 等于或不等于0,所以没必要非的用第几位去判断. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return f

剑指Offer面试题40(Java版):数组出现一次的数字

题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次. * 请些程序找出这两个只出现一次的数字.要求时间复杂度为O(n),空间复杂度为O(1) 例如输入数组{2,4,3,6,3,2,5,5},因为只有4,6这两个数字只出现一次,其他数字都出现了两次,所以输出4,6 这是一个比较难的题目,很少有人在面试的时候不需要提示一下子想到最好的解决办法.一般当应聘者想了几分钟那个后还没有思路,面试官会给出一些提示. 我们想到异或运算的一个性质:任何一个数字异或它自己都等于0,也就是说,如果我们从头到