• 某整形数组中除了两个单身整数外, 其余的整数都是成对出现的, 利用C/C++代码求出这两个单身整数。 要求: 时间复杂度o(n), 空间复杂度o(1)------某公司招聘试题


           先看看这个题目:某整形数组中除了两个单身整数外, 其余的整数都是成对出现的, 利用C代码求出这两个单身整数。 要求: 时间复杂度o(n), 空间复杂度o(1).


           我们先用最傻瓜的方式来做吧:

    #include <iostream>
    using namespace std;
    
    // 时间复杂度为o(n^2), 空间复杂度为o(1), 不符合要求
    void findSoleNumbers(int a[], int n, int &e1, int &e2)
    {
    	int i = 0;
    	int j = 0;
    	int continueFlag = 0; // 控制外层for, 推断是否过滤当前整数
    	int numberFlag = 0; // 标志第一个、第二个单身整数
    
    	for(i = 0; i < n; i++)
    	{
    		continueFlag = 0;
    		for(j = 0; j < n; j++)
    		{
    			if(j != i && a[j] == a[i])
    			{
    				continueFlag = 1;
    				break;
    			}
    		}
    
    		if(1 == continueFlag) //  该整数是成双成对的。 过滤掉
    		{
    			continue;
    		}
    		
    		// 可怜的单身整数
    		if(0 == numberFlag++)
    		{
    			e1 = a[i];
    		}
    		else
    		{
    			e2 = a[i];
    		}
    	}
    }
    
    int main()
    {
    	{
    		int a[] = {1, 5, 3, 5, 1, 2};
    		int n = sizeof(a) / sizeof(a[0]);
    		int e1 = 0;
    		int e2 = 0;
    
    		findSoleNumbers(a, n, e1, e2);
    		cout << e1 << endl;
    		cout << e2 << endl;
    		cout << "--------------------------" << endl;
    	}
    
    
    	{
    		int a[] = {1, 1, 2, 5, 4, 5, 2, 4, 3, 0};
    		int n = sizeof(a) / sizeof(a[0]);
    		int e1 = 0;
    		int e2 = 0;
    
    		findSoleNumbers(a, n, e1, e2);
    		cout << e1 << endl;
    		cout << e2 << endl;
    		cout << "--------------------------" << endl;
    	}
    
    	return 0;
    }
           结果为:

    3
    2
    --------------------------
    3
    0
    --------------------------


           上面程序时间复杂度不满足题目要求。

    当然, 有的朋友可能会想到排序, 思路是能够, 可是, 时间复杂度依旧不是o(n),  所以, 排序法我就不介绍了。


          

           因为数组中整数的范围并没有给出。 所以, 也不太适合用计数的方法来做。 那怎么办呢? 假如该题目中的整形数组中仅仅有一个单身整数。 那也好办, 例如以下:

    #include <iostream>
    using namespace std;
    
    // 时间复杂度为o(n), 空间复杂度为o(1), 不符合要求
    void findSoleNumber(int a[], int n, int &e)
    {
    	e = 0;
    	int i = 0;
    	for(i = 0; i < n; i++)
    	{
    		e ^= a[i];
    	}
    }
    
    int main()
    {
    	{
    		int a[] = {1, 5, 3, 5, 1};
    		int n = sizeof(a) / sizeof(a[0]);
    		int e = 0;
    
    		findSoleNumber(a, n, e);
    		cout << e << endl;
    		cout << "--------------------------" << endl;
    	}
    
    	{
    		int a[] = {0, 5, 1, 5, 1, 2, 2};
    		int n = sizeof(a) / sizeof(a[0]);
    		int e = 0;
    
    		findSoleNumber(a, n, e);
    		cout << e << endl;
    		cout << "--------------------------" << endl;
    	}
    
    	return 0;
    }
           结果:

    3
    --------------------------
    0
    --------------------------


            上面的方法虽然没有彻底解决这个问题, 但已经提供了思路的雏形了。 以下。 我直接给出可行的方法。 代码本身就是最好的解释, 所以不再解释。 代码例如以下:

    #include <iostream>
    using namespace std;
    
    // 在num的二进制中查找第一个出现1的位置
    int findFirstBitEquOne(int num)
    {
    	int bitIndex = 0;
    	while(bitIndex < 32 && 0 == (num & 1))
    	{
    		num >>= 1;
    		bitIndex++;
    	}
    
    	return bitIndex;
    }
    
    // 推断num二进制的bitIndex位上的数是否为1
    bool isBitOne(int num, int bitIndex)
    {
    	return ( (num >>= bitIndex) & 1);
    }
    
    // 时间复杂度为o(n), 空间复杂度为o(1)
    void findSoleNumbers(int a[], int n, int &e1, int &e2)
    {
    	e1 = 0;
    	e2 = 0;
    
    	int i = 0;
    	int result = 0;
    	for(i = 0; i < n; i++)
    	{
    		result ^= a[i]; // 最后的result肯定是两个单身整数的异或值
    	}
    
    	int bitIndex = findFirstBitEquOne(result);
    
    	for(i = 0; i < n; i++)
    	{
    		// 对于每个整数, 依据isBitOne原则进行分组, 两个单身整数必定落在不同的组中, 而成双成对的整数必定落在同一组中
    		
    		if(isBitOne(a[i], bitIndex)) // 组1
    		{
    			//cout << "debug1: " << a[i] << endl;
    			e1 ^= a[i];
    		}
    		else                         // 组2
    		{
    			//cout << "debug2: " << a[i] << endl;
    			e2 ^= a[i];
    		}
    	}
    }
    
    int main()
    {
    	{
    		int a[] = {1, 5, 3, 5, 1, 2};
    		int n = sizeof(a) / sizeof(a[0]);
    		int e1 = 0;
    		int e2 = 0;
    
    		findSoleNumbers(a, n, e1, e2);
    		cout << e1 << endl;
    		cout << e2 << endl;
    		cout << "--------------------------" << endl;
    	}
    
    
    	{
    		int a[] = {1, 1, 2, 5, 4, 5, 2, 4, 3, 0};
    		int n = sizeof(a) / sizeof(a[0]);
    		int e1 = 0;
    		int e2 = 0;
    
    		findSoleNumbers(a, n, e1, e2);
    		cout << e1 << endl;
    		cout << e2 << endl;
    		cout << "--------------------------" << endl;
    	}
    
    	return 0;
    }
          结果例如以下:

    3
    2
    --------------------------
    3
    0
    --------------------------

         异或的思路。 非常巧妙, 以后要注意。  好了。 本文先到此为止。



  • 相关阅读:
    MSCRM2011 在Form里创建一个密码栏
    MSCRM 2011 可视化Ribbon编辑工具,超级强大!
    C# List去重
    理解Dynamic CRM2011 Ribbon里Sequence 和TemplateAlias意思
    SQL 语法大全
    SQL语句case关键字的用法
    ASP.NET 导出Excel时,某单元格内一部分文字加粗加下划线
    ASP.NET 导出Excel时,出现CLSID {0002450000000000C000000000000046} ,拒绝访问。
    通过DOM节点操作来获取表单信息
    嗨,博客园
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7214725.html
Copyright © 2020-2023  润新知