算法-只出现一次的数字(原理讲解)

这三道题目也是Leetcode上的,考察的是对位运算的掌握程度。当然用HashMap也是可以做的。这里只讲位运算。

1、只出现一次的数字(I)

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1
示例 2:

输入: [4,1,2,1,2]
输出: 4

我们知道两个相同的数字异或后结果为0,任何数字和0异或等于它本身,所以我们将数组所有元素异或就得到解。

    public int singleNumber(int[] nums) {
        int n=0;
        for(int i=0;i<nums.length;i++){
            n^=nums[i];
        }
        return n;
    }

2、只出现一次的数字(II)

137. 只出现一次的数字 II

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,3,2]
输出: 3
示例 2:

输入: [0,1,0,1,0,1,99]
输出: 99

我在这里直接给出一个通用解法,在1个非空整数数组,除了某个元素出现1次以外,其他数字都出现k次。

我们对数组中每个数字的每一位进行检查,如果统计对应位的1的数量不为k的整数倍时,说明其是组成目标数字的位,反之不是,然后用按位或的操作就可以得到结果了
当k=3时,就是本题的答案,当k=2时,就是1的答案。

//nums:输入数组  k:除某个元素外,剩余元素都出现k次
public int singleNumber(int[] nums,int k) {
	int result=0;
	for(int i=0;i<32;i++){
		int mask=1<<i;
		int maskCount=0;
		for(int n:nums){
			if((n&mask)!=0){
				maskCount++;
			}
		}
		if(maskCount%k!=0){
			result|=mask;
		}
	}
	return result;
}

3、只出现1次的数字(III)

260. 只出现一次的数字 III

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

示例 :

输入: [1,2,1,3,2,5]
输出: [3,5]
注意:

结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

本题考察的仍然是位运算,延续1的思路,我们首先可以把所有数据异或,最后剩下的就是那两个只出现一次的元素(记录为a、b)的异或值。

其中,这个值的非零位必然是属于其中一个的,而不属于另一个,这样的话我们就将数据分成了两部分,除a外的所有在此位和a相同的位元素组成的数组 同理b也是。

    public int[] singleNumber(int[] nums) {
		int result=0;
		for(int i:nums){
			result^=i;
		}
		int a=0,b=0;
		for(int i=31;i>=0;i--){//找到第一个非0位
			int mask=1<<i; 
			if((result&mask)!=0){//找到那一位
				for(int n:nums){//遍历数组,将数组分为两类
					if((n&mask)!=0){
						a^=n;
					}else{
						b^=n;
					}
				}
				break;
			}
		}
		return new int[]{a,b};
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章