数字在数组中出现一次的情况

1.数字在数组中出现一次的情况

(《剑指OfferP211,《编程之美》P38

1)问题描述:

一个数组中,一个或两个数字只出现了一次,其他数字都出现了两次,找到这两个数字。

2)解决思路

解法一:遍历列表,使用哈希表记录下每个数字出现的次数,每次遇见一个新的数字,则在哈希表中增加一个元素;遇见相同的数字,即该数字出现两次,则从哈希表中将该元素删除。

时间复杂度:O(n);空间复杂度:O(1)(最好情况)O(n)(最坏情况)

解法二:只有一个数字出现一次的情况,可使用数组中所有数字异或,结果即为所需的数字;

若有两个数字出现一次,则异或的结果一定不为0,该结果的二进制表示中至少有一位上为1.取该结果第一个为1的位置,即为第N位。将数组中的所有数字分为第N位为10两个不同的数组,两个数组中分别含有一个所需求的数字结果,同样分别采取异或的方法即可获得。

时间复杂度:O(n);空间复杂度:O(1)

代码实现:

    //num1,num2分别为长度为1的数组。传出参数
    //将num1[0],num2[0]设置为返回结果
    public class Solution {
        public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
            if (array == null || array.length <= 1)
                return;
            // 进行一次遍历,将所有元素异或
            int result = 0;
            for (int data : array)
                result ^= data;

            // 先找到结果值result的第一个不为0的二进制位置index
            if (result == 0) return;
            int index = 1;
            for (; (result & index) == 0; index <<= 1);

            // 再次遍历,将index位是否为1分为两个数组分别进行异或,得到的结果值即为所求
            num1[0] = 0; num2[0] = 0;

            for (int data : array) {
                // 注意比较该位是否为1
                if ((data & index) == index)
                    num1[0] ^= data;
                else
                    num2[0] ^= data;
            }
        }
    }


// (两个)数字在数组中出现一次的情况

#include "stdafx.h"
#include <iostream>
using std::cout; using std::cin;

//异或算法得到结果
//参数:data_array操作数组,length表示数组长度
int Calculate_Fun(int data_array[], int length)
{
	int result = 0;
	for (int i = 0; i < length; i++)
	{
		result ^= data_array[i];//异或过程
	}
	return result;
}

//找到结果中第一个非零值的位置n(从末位开始)
int Find_N(int result)
{
	int index = 0;
	const int SIZE_OF_BIT = 8;
	while (((result & 1) == 0) && (index < SIZE_OF_BIT * sizeof(int)))
	{
		result >>= 1;
		++ index;
	}
	return index;
}



int _tmain(int argc, _TCHAR* argv[])
{
	//输入待测试数组
	//printf("输入包含有数据的数组:");
	const int MAXSIZE = 10;
	//int data_array[MAXSIZE];
	//for (int i = 0; i < MAXSIZE; i++)
	//{
	//	cin >> data_array[i];
	//}

	//调试
	int data_array[MAXSIZE] = {1,1,2,3,3,4,5,5,6,6};

	//第一次异或遍历
	int reslut;
	reslut = Calculate_Fun(data_array,MAXSIZE);

	if (reslut == 0)
	{
		printf("数组中没有只出现一次的数组");
	}
	else
	{
		//找到结果中第一个非零值的位置n(从末位开始)
		int index = Find_N(reslut);
		//划分数组
		int judge_num = 1;
		for (int i = 0; i < index; i++)
		{
			judge_num <<= 1;
		}
		int left_data[MAXSIZE / 2], right_data[MAXSIZE / 2];
		int left_index = 0, right_index = 0;
		for (int i = 0; i < MAXSIZE; i++)
		{
			if ((data_array[i] & judge_num) == 0)
			{
				left_data[left_index] = data_array[i];
				++left_index;
			}
			else
			{
				right_data[right_index] = data_array[i];
				++right_index;
			}
		}
		printf("得到的两个只出现一次的数字分别为:%d,%d", 
			Calculate_Fun(left_data, MAXSIZE / 2),
			Calculate_Fun(right_data, MAXSIZE / 2));
	}
	return 0;
}

解法三:(适用于缺少某一个ID的情况)使用不变量法,即求取总和或者平方和,减去当前数组总和或平方和,建立方程组求解。

	a = a + b;
	b = a - b;
	a = a - b;


2.实现不用第三存储变量temp直接实现交换两个变量的值

(《深入理解计算机系统》P34)这里要注意如*x = *y的情况,因为a^a=0

 

void inplace_swap(int *x,int *y){
	*y = *x ^ *y;
	*x = *x ^ *y;
	*y = *x ^ *y;
}

实现流程:(使用了a^a=0,前面例子中也使用了该方法)

*x                        *y
a                         b
a                       a^b
a^a^b = b               a^b
b                   a^b^b=a

实现方法二:(基于加减法)

《剑指OfferP239  这里要注意相加后会不会有溢出情况

	a = a + b;
	b = a - b;
	a = a - b;

实现方法三:(适用于Java变量缓存机制)

x = y + 0 * (y = x);  // 先将y参与运算,然后将x值赋给y,最后再将结果(也就是y)赋给x 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值