码迷,mamicode.com
首页 > 编程语言 > 详细

算法-找出其他出现偶数次的数组中出现1次,2次,3次的数

时间:2015-04-30 21:53:18      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:算法   c++基础   

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <iostream>
#include<vector>
#include<string>
#include<set>
#include<unordered_set>
#include<queue>
#include<map>
using namespace std;

//一。 找出一个出现一个次的数
/*
思路就是用异或,异或的作用能够将bit位相同的1,1   0,0变成0 
这正好与偶数的思路相应。把所有数异或起来,就会发现,只出现一次的数上面的1的bit位才会被保留。
*/
int findone(int a[],int n)
{
    int ans = 0;
    for (int i = 0; i < n; i++)
    {
        ans ^= a[i];
    }
    return ans;
}



//二。找出两个出现一次的数
/*
出现两个1次的数再用1的方法就不起效了,但是有一种办法,就是把整个数组分成两部分。
每一部分包括一个数,这样就可以转换为求出现一次数的方法。
如何分解呢,首先需要找出这两个数的区别:
 a:  0 0 1 1 
 b:  0 1 0 1
 异或:0 1 1 0
我们会发现a和b的比特位异或,有4种情况,其中两种情况结果是1.当结果比特位异或等于1的时候,a和b的比特位肯定不同。
这就是区别,我们可以通过找某一位比特位是否为1来区分成2个组。
*/
int findbit1(int n)
{//找出低位开始第一个为1的比特位,其他清0
    return n&~(n - 1);   // n&-n也可以
}
void findtwo(int a[],int n)
{
    int ans1 = 0, ans2 = 0;
    int flag = findone(a, n); //全部异或,结果=a^b  其他变为0;
    flag = findbit1(flag);
    for (int i = 0; i < n; i++)
    {
        if (a[i] & flag)
            ans1 ^= a[i];
        else
            ans2 ^= a[i];
    }
    cout << ans1 << endl;
    cout << ans2 << endl;
}

//三。找出3个出现1次的数
/*
这次更加困难了,因为无法直接划分成2组。 比如a,b,c
a 0 0 0 0 1 1 1 1
b 0 0 1 1 0 0 1 1
c 0 1 0 1 0 1 0 1
r 0 1 1 0 1 0 0 1
当结果为1的时候a,b,c有两种可能,一种是0 0 1 还有一种是 1 1 1这就无法区分是哪种情况了,比较棘手
网上有种方法是不管三七二十一,先按 0 0 1这种情况算,然后得出的ans1和ans2比较 再分多种情况,比较复杂。
下面这种用到了反证法还有函数构造过程比较复杂,如果理解了,直接就噜出来了,比较推荐
1. 首先异或所有数  x=a^b^c.....其他异或=0 
2. 再次用x异或所有数  x^a[i] 。 这样对于出现偶数次的没有区别,因为我们不关心他们的实际大小
但是  x^a,  x^b ,  x^c  这三个数 就起到了很大的变化。我们的目标是将这三个数划分成唯一的两组。
我们会发现  x^a ^ x^b ^ x^c =0, 而且三个数都不可能为0,而且互不相同。(因为x^a=b^c,b不等于c所以b^c不等于0)
然后做一个技巧,令 n1=f(x^a),n2=f(x^b),n3=f(x^c),ni=f(x^a[i])  其中f的作用是保留低位最近那个1其他全为0 ( XXXXX1000变为 000001000)
然后n1,n2,n3中就都有且只有一个位为1,现在区别n1,n2,n3的问题又成为
n1 0 0 0 0 1 1 1 1
n2 0 0 1 1 0 0 1 1
n3 0 1 0 1 0 1 0 1
r  0 1 1 0 1 0 0 1
之前是三个数可能同时为1,也可能只有一个为1,这样r=1;  但是三个数不可能同时为1. 不然与n1^n2^n3=0矛盾(因为x^a ^ x^b ^ x^c =0保证了任意一位上不可能三个1)
最终:
只需要 p=f(n1^n2^n3)  挑选 p&f(x^a[i])!=0 为一组  ==0为一组就行了
*/
void findthree(int a[], int n)
{
    int x = findone(a, n);
    int p = 0;
    for (int i = 0; i < n; i++)
        p ^= findbit1(x^a[i]);
    p = findbit1(p);
    int ans1 = 0, ans2 = 0, ans3 = 0;
    for (int i = 0; i < n; i++)
    {
        if (p&findbit1(x^a[i]))
            ans1 ^= a[i];
    }
    cout << ans1 << endl;
    //将ans1踢出
    for (int i = 0; i < n; i++)
    {
        if (ans1 == a[i])
        {
            swap(a[i], a[n - 1]);
            break;
        }
    }
    findtwo(a, n - 1);
}
int main(){

    int a1[] = { 1, 1, 2, 2, 3, 4, 4 };
    int a2[] = { 1, 1, 2, 2, 3, 4, 4 ,5};
    int a3[] = { 6, 1, 1, 2, 2, 3, 4, 4, 5 };
    cout << "找一个" << endl;
    cout << findone(a1, sizeof(a1) / sizeof(int))<<endl;
    cout << "找两个" << endl;
    findtwo(a2, sizeof(a2) / sizeof(int));
    cout << "找三个" << endl;
    findthree(a3, sizeof(a3) / sizeof(int));
    getchar();
    getchar();
    return 0;
}

算法-找出其他出现偶数次的数组中出现1次,2次,3次的数

标签:算法   c++基础   

原文地址:http://blog.csdn.net/cq361106306/article/details/45399233

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