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

#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;
}
时间: 2024-10-05 15:37:02

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

找出现有Vector或ArrayList或数组中重复的元素&amp;给现有Vector或ArrayList或数组去重

//直接上代码: public static void main(String[] args) { List<Integer> list = new Vector<Integer>(20); for (int i = 0; i < 10; i++) { list.add(i % 3); list.add(i % 6); list.add(i % 2); list.add(i % 4); } System.out.println("原始元素:" + list

[算法]找出数组当中的中枢元素

给定一个整型数组,找出pivot,使得对于任意i < pivot,a[i] <=a[pivot],对于i > pivot,a[i]>=a[pivot],只能用一个额外的数组,和少量空间. 思路 1.使用一个数组t记录,t[i]记录的是a[0]~a[i]的最大值 int *t = new int[n]; for(int i = 0, max = ~0; i < n; ++i){ if(a[i] > max){ max = a[i]; } t[i] = max; } 2.从

数组a[n]中存放1-n中的n-1个数,给出算法找出重复的那一个数

问题描述: 数组a[n]中存放1-n中的n-1个数,给出算法找出重复的那一个数. 算法一: 对数组a[n]进行冒泡排序,如果冒泡所得的最值和前一个最值相等,则该最值为重复的数. 分析: 该算法时间复杂度最坏的情况为O(n的2次方),在空间开销上只需要一个额外的交换空间. 如何将时间开销减小呢?下面给出另外一种算法 算法二: 给定另外一个数组b[n],将a[n]中的数作为数组b的索引,然后遍历b[n],如果未访问过,则标记:如果已经访问过,则该索引就为重复的数. 分析: 该算法时间复杂度能够达到最

高效的算法找出中间所有A[i] = i的下标

给定一个排好升序的数组A[1].A[2].--.A[n],其元素的值都两两不相等.请设计一高效的算法找出中间所有A[i] = i的下标.并分析其复杂度. 解析:首先分析一下这个数组,假设其中某个位置的A[i] = i,那么可以肯定的值,之前的A[x] > x,之后的A[x] < x.还有一个显而易见的性质就是中间的A[i]=i一定是连续存在的,不可能跨区域存在,因为这个数组是升序的. 我给出的方法是二分查找,具体的做法是:我们假设一个新数组B,其元素是A[i] - i的值,这样的话,B[i]

算法——找出缺失的整数

一.前言 最近智商持续掉线,隐约有种提前犯了阿兹海默症的感觉,偶像剧看多了就是容易智商持续掉线,前一整子关注了个算法的公众号,今天也终于捡着一篇能看懂的了,感觉非常的涨姿势,整篇看下来觉得自己有了很大的提升,仿佛就差一点就看懂了. 以下是原文的链接,为了防止链接被破坏,为了维护涨过的姿势还找得到的和平,阿婆,可爱又迷人的反派角色这里决定开个随笔整理一下文章内容和评论里面的代码,等. 原文请戳这里 http://blog.jobbole.com/106521/ 二.请看正文 第一题:请听题,要把大

【转】已知一个数出现的次数严格超过了一半,请用O(n)的复杂度的算法找出这个数

原文转自:http://blog.csdn.net/zhq651/article/details/7930284 方法1:既然过半,那么用这个数与其他数配对的话,剩余的数字一定还是过半的这个数字.因此可以通过不断删除不同的2个数,直到没有不同的2个数,那么这个数就是要找的数.证明:最坏情况下,只有这个数同别的数配对,并且被删除,剩下的仍旧是这个数,因此得证. 转自:http://www.cnblogs.com/python27/archive/2011/12/15/2289534.html 例:

写一个查找算法找出数组中相同的元素

1 import java.util.ArrayList; 2 3 public class Test { 4 5 // 原始数据data.假设data数组中的数据元素已经按照某种顺序排好. 6 // 但是,该数组中的数据元素重复出现. 7 // 我们的目的是查找.解析data数组中重复出现的某元素. 8 // 比如,在这个data数组中,元素'C'在数组位置2,3重复出现两次. 9 // 注意!有些元素没有重复出现,比如元素'B'. 10 private String[] data = { "

找出文件1中有而文件2中没有的数据

// 使用stream方法实现 public static List<String> fileterData() throws IOException { String file1Content = new String(Files.readAllBytes(Paths.get(".\\src\\main\\resources\\File1"))); String file2Content = new String( Files.readAllBytes(Paths.get

感知哈希算法&mdash;&mdash;找出相似的图片

Google 图片搜索功能         在谷歌图片搜索中, 用户可以上传一张图片, 谷歌显示因特网中与此图片相同或者相似的图片.         比如我上传一张照片试试效果: 原理讲解         参考Neal Krawetz博士的这篇文章, 实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张图片的指纹越相似, 说明两张图片就越相似. 但关键是如何根据图片计算出"指纹&qu