Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

 

感谢cnblog博主feiling,这篇博客一方面参考了feiling的博客,也加入了自己的一些看法。

[解题思路]

要求线性时间复杂度,同时空间复杂度为O(1),即只允许开常数个空间。

最直接的思路是对每一个元素尝试查找是否有重,如果没有重,就返回。

复制代码
class Solution {
public:
    int singleNumber(int A[], int n) {
        int i = 0, j = 0;
        for(i = 0;i < n;i++)
        {
            for(j = 0;j < n;j++)
            {
                if(i == j)
                    continue;
                else if(A[i] == A[j])
                    break;
                    else continue;
            }
            
            if(j == n)
                return A[i];
        }
	return 0;
    }
};
复制代码

不幸的是虽然是o(n2)的时间复杂度,但是还是超时了。于是乎就得想一个o(n)的算法。

o(n)的算法只能是线性扫描一遍,可能的相法是位运算。对于异或来说:

1. 异或运算是可交换,即 a ^ b = b ^ a

2. 0 ^ a = a

那么如果对所有元素做异或运算,其结果为那个出现一次的元素,理解是a1 ^ a2 ^ ....,可以将所有相同元素交换至相邻位置,首先运算相同元素,则会产生(n - 1)/2个0异或积,剩余一个单一元素,他们的异或积为这个单一元素自己,得解。

复制代码
复制代码
 1 public class Solution {
 2     public int singleNumber(int[] A) {
 3         // Note: The Solution object is instantiated only once and is reused by each test case.
 4         if(A == null || A.length == 0){
 5             return 0;
 6         }
 7         int result = A[0];
 8         
 9         for(int i = 1; i < A.length; i++){
10             result = result ^ A[i];
11         }
12         return result;
13     }
14 }
复制代码
复制代码

本题扩展

1.一个数组中有两个元素只出现一次,其他所有元素都出现两次,求这两个只出现一次的元素

	public static List findOnlyNum(int[] array){
		List<Integer> list = new ArrayList<Integer>();
		for(int i = 0 ;i<array.length;i++){
			int j = 0;
			for(;j<array.length;j++){
				if(i==j){
					continue;
				}
				if(array[i]==array[j]){
					break;
				}
			}
			if(j==array.length){
				list.add(array[i]);
			}
		}
		return list;
	}

[解题思路]

将数组所有元素都进行异或得到一个不为0的结果,根据这个结果中的不为0的某一位将数组分成两组

将两组中的元素进行异或,如两个数组的异或值都不为0,则得到最后结果

	public static List findOnlyNum(int[] array){
		List<Integer> list = new ArrayList<Integer>();
		int result = 0;
		int result1 = 0;
		int result2 = 0;
		//我们需要找到一个条件,给这两个出现过一次的数找出可以区分的条件。
		//相同的数异或等到的结果0,那么整个序列异或的结果就是这两个出现过一次的数的异或。
		for(int i = 0 ;i<array.length;i++){
			result^=array[i];
		}
		//找出他们的不同之处,前面我们讲过,异或按位操作是相同的为0 ,不同的为1,那么这两个数异或的结果转换成2进制时,低位出现第一个1时就可以区分他们。
		String binaryResult = Integer.toBinaryString(result);
		int index = binaryResult.length() - (binaryResult.lastIndexOf("1")+1);  
		//在index位为1的分为一组,为0的分为一组,将序列划分为两个序列
		for(int i =0;i<array.length;i++){
			if(((array[i]>>index)&1)==1){
				result1^= array[i];
			}else{
				result2^=array[i];
			}
		}
		list.add(result1);
		list.add(result2);
		return list;
	}
假设二个不同数值是a,b;那么 s = a^b; 然后求的s中第一次出现1的位 置k,根据异或运算特性,第一次出现1的地方就是这二个数位有区别的地方,比如1001 0101 与 1100 0001 得到异或 结果是0101 0100 .那么第一次出现1的地方是第三位,a的第三位是1而b是0 。 接着遍历数值,找出第三位是1的数值就异或,得到的结果就是其中一个数与其他出现二次的数求异或,因为出现二次的 数异或得到为0所 有最后结果就是所求其中一个数。
最后s与该数求异或就得到另一个数。

2.一个数组中有一个元素只出现1次,其他所有元素都出现k次,求这个只出现1次的元素

[解题思路]

当k为偶数时,同lss

当k为奇数时,将数组中每个元素的每一位相加mod k,得到结果即位出现1次的元素,时间复杂度O(nlen),空间复杂度为O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值