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

题目大意: 给定你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;
}

代码二(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);
    }
}

时间: 2024-10-24 13:52:54

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

9.5位操作(三)——给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数

/** * 功能:给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数. * (一个略大一个略小.) */ 三种方法: 方法一:蛮力法 方法二:位操作法 <span style="white-space:pre"> </span>/** * 方法:位操作法 * 思路:获取后一个较大的数 * 1)计算c0和c1.c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数. * 2)将最右边.非拖尾0变为1,其位置为p=c1+c0. * 3)将位p

c语言:找出1到4000中,数字的各位数之和能被4整除的数有多少个?

找出1到4000中,数字的各位数之和能被4整除的数,如:745:7+4+5=16,16可以被4整除:28:2+8=10,10不能被4整除:745就是这样的特殊数字,而28不是,求:这样的数字共有多少个? 解: (1)对于4000,4+0+0+0=4,显然4000是满足条件的数字: (2)对于1到3999,我们把每个数字看成4位[][][][]的形式,第一位[]取0到3,后3位取[0][0][0]到[9][9][9],用sum表示4位数字的和: 2.1:若后3位为一个奇数,则第1位取1或3,必定可

(算法:二分查找)在排序数组中,找出给定数字出现的次数

题目: 在排序数组中,找出给定数字出现的次数 思路: 既然出现排序数组,很容易想到二分查找,时间复杂度为O(logn): 先通过二分查找找到最左边出现该数字的下标left(如果没找到,则返回-1),然后通过二分查找找到最右边出现该数字的下表right(如果没找到,则返回-1),然后right-left+1就是出现的次数: 代码: #include <iostream> using namespace std; int BinarySearchCount(int *array,int len,i

[leetcode 周赛 160] 1237 找出给定方程的正整数解

1237 Find Positive Integer Solution for a Given Equation 找出给定方程的正整数解 问题描述 给出一个函数 f(x, y) 和一个目标结果 z,请你计算方程 f(x,y) == z 所有可能的正整数 数对 x 和 y. 给定函数是严格单调的,也就是说: f(x, y) < f(x + 1, y) f(x, y) < f(x, y + 1) 函数接口定义如下: interface CustomFunction { public: // Ret

找出此产品描述中包含N个关键字的长度最短的子串

阿里巴巴笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号:再给定N个英文关键词,请说明思路并变成实现方法. String extractSummary(String description , String[] keyWords) 目标:找出此产品描述中包含N个关键字的长度最短的子串(20分) W0 W1 W2 W3  Q0 W4 W5 Q1 W6 W7 W8 Q0 W9 Q1 P335 <编程之美>上的参考代码: int nTarget = N + 1

找出N个数据中的最大的K个数据---堆排序

从N个数据中找出最大的K个数据,而且这里有一个限制:内存里存不下所有的N个数据,但是可以存下K个数据.这就让我们打消了用排序的方法来解的念头. 在这里我们使用堆排序来完成. 因为我们只能有K个数据那么大的空间,所以我们建一个K大的堆,将N的前K个数据插入到堆中,然后调整堆.(对于堆结构不了解的可以查看我微博  http://helloleex.blog.51cto.com/10728491/1768758) 对于最大的K个数据,我们要怎么找出来呢.我们首先要确定我们是要用大顶堆还是小顶堆.  用

找出n个字符串中出现次数最多的字符串。

1. 找出n个字符串中出现次数最多的字符串. C/C++: char* find(char **data,int n); Java: String find(String data[]); 说明: 1. data是字符串数组,n是数组中字符串的个数,返回值为出现次数最多的字符串. 2. 若结果有多个,返回任意一个即可 3. 不得使用任何库函数/API,如需使用类似功能, 请自行实现 4. 算法效率尽可能高,尽量少的使用内存空间 5. 必须要有代码注释和算法说明. 例如:data里面的数据是{“p

c语言代码编程题汇总:找出三个数据中最大的数值

找出三个数据中最大的数值 程序代码如下: 1 /* 2 2017年3月9日12:04:37 3 功能:找出三个数据中最大的数值 4 */ 5 #include"stdio.h" 6 7 int fun(int,int,int); 8 9 int main() 10 { 11 int a ,b,c; 12 13 printf("please input three number: \n"); 14 15 scanf("%d %d %d",&

9.11排序与查找(五)——有个排序后的字符串数组,其中散布着一些空字符串,找出给定字符串的位置

/** * 功能:有个排序后的字符串数组,其中散布着一些空字符串,找出给定字符串的位置. */ /** * 思路:对二分查找法做修改,与mid比较的地方,如果mid为空字符串,则将mid换到离它最近的非空字符串的位置. * @param strings * @param str * @return */ public static int search(String[] strings,String str){ if(strings==null||str==null||str=="")