码迷,mamicode.com
首页 > 其他好文 > 详细

位运算 找出给定的数中其他数都是两个,有两个是一个的数

时间:2015-04-05 11:43:50      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:

题目大意: 给定你n个数, 其中有n-2个数都是两两成对的,有两个是单独出现的,如n = 8, 2 3 2 5 3 6 4 6, 这时候4和5是单独的两个,所以答案就是4,5,其中n的范围是1e6.

思路: 之前做过找一个单独的数的题,那个题是用一个比较巧妙的方法来做的,不过这个也是一类经典问题,用到了强大的位运算,有了那个题的基础再来做这个题就简单了.(附:找一个的题目链接). 刚开始我是用了O(nlogn)的时间复杂度来做的,先排序,然后用类似找一个的方法找出第二个.我觉得对于1e6的数据量能过,还有一个就是比较经典的方法,就是还是将他们都异或出来,最后的结果就是那两个单独的数异或的结果,假设为t,因为相同两个数的异或结果为0, 再根据异或的定义:相同为0, 不同为1, 所以 找出这两个数不相同的部分, 就能把数组分成两类, 不相同的部分就是异或的结果从右边起第一个非0的位置,也就是第一个1的位置,假设这个位置是index, 那么数组中这一位要么是0,要么是1,因为是二进制嘛,所以这时候就将数组分成了两类,一类是index这一位是0的,一位是1的,将t分别与他们异或,则异或index为0的,得出的结果是index位为1的那个答案.这句话可能不好理解,举个例子,假设3和5是最后的答案,那么3^5=6, 二进制表示就是011^101=110, 所以用他们异或的结果6去与数组中的倒数第二位为0的异或的结果为011,也就是3, 因为就相当于6^5,所以等于3.

代码一(O(nlogn))

技术分享
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000005;
int n, arr[N];
int main()
{
    while (~scanf("%d", &n))
    {
        for (int i = 0; i < n; i++)
        scanf("%d", &arr[i]);
        sort(arr, arr + n);//排序时间复杂度nlogn
        int t = arr[0];
        int pre = arr[0];
        int ans[2] = {0, 0}, k = 0;
        for (int i = 1; i < n; i++)
        {
            t = t ^ arr[i];
            if (t != 0 && t != arr[i])
            {
                ans[k++] = pre;
                t = arr[i];
            }
            pre = arr[i];
        }
        if (k == 1)
            printf("%d %d\n", ans[0], arr[n - 1]);
        else
            printf("%d %d\n", ans[0], ans[1]);    
    }
    
    return 0;
}
View Code

代码二(O(n))

技术分享
/*************************************************************************
    > File Name: find_two_diff_number.cpp
    > Author: 
    > Mail: 
    > Created Time: 2015年04月04日 星期六 17时13分22秒
 ************************************************************************/

#include<iostream>
#include <cstdio>

using namespace std;
const int N = 1e7;
int arr[N];
int n;
int main()
{
    
    while (~scanf("%d", &n) && n)
    {
        for (int i = 0; i < n; i++)
            scanf("%d", &arr[i]);
        int t1, t2, t = arr[0];
        for (int i = 1; i < n; i++)
        {
            t ^= arr[i];//找出两个不同的异或结果
        }
        int off = 1;
        t1 = t2 = t;
        while ((t & off) == 0)//找出第一个1对应的位置index
            off <<= 1;
        for (int i = 0; i < n; i++)
        {
            if (arr[i] & off)//将index对应位置为1的分为一类
                t1 ^= arr[i]; 
            else//其它的就是为0的
                t2 ^= arr[i];
        }
        if (t1 > t2)
        {
            t = t1;
            t1 = t2;
            t2 = t;
        }
        printf("%d %d\n", t1, t2);
    }
}
View Code

 

位运算 找出给定的数中其他数都是两个,有两个是一个的数

标签:

原文地址:http://www.cnblogs.com/Howe-Young/p/4393718.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!