1.数字在数组中出现一次的情况
(《剑指Offer》P211,《编程之美》P38)
(1)问题描述:
一个数组中,一个或两个数字只出现了一次,其他数字都出现了两次,找到这两个数字。
(2)解决思路
解法一:遍历列表,使用哈希表记录下每个数字出现的次数,每次遇见一个新的数字,则在哈希表中增加一个元素;遇见相同的数字,即该数字出现两次,则从哈希表中将该元素删除。
时间复杂度:O(n);空间复杂度:O(1)(最好情况),O(n)(最坏情况)
解法二:只有一个数字出现一次的情况,可使用数组中所有数字异或,结果即为所需的数字;
若有两个数字出现一次,则异或的结果一定不为0,该结果的二进制表示中至少有一位上为1.取该结果第一个为1的位置,即为第N位。将数组中的所有数字分为第N位为1和0两个不同的数组,两个数组中分别含有一个所需求的数字结果,同样分别采取异或的方法即可获得。
时间复杂度: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
实现方法二:(基于加减法)
《剑指Offer》P239 这里要注意相加后会不会有溢出情况
a = a + b;
b = a - b;
a = a - b;
实现方法三:(适用于Java变量缓存机制)
x = y + 0 * (y = x); // 先将y参与运算,然后将x值赋给y,最后再将结果(也就是y)赋给x