【Leetcode】Single Number 系列问题

这三道题目很考察bit操作思路。使用了下列几个技巧。

1.如何取得一个int数字二进制表示的每一位,方法就是使用逻辑右移操作,逐位与1做&操作;

2.亦或xor是一个很关键的操作,0与任意一个数做偶数次xor结果是0,奇数次结果是1。

3.位操作是满足交换律的,因为每一个bit是满足的。

4.如何得到一个int的最右侧的第一个1?方法是与其相反数做&。因为相反数是取反加一,取反以后,第一个1右侧的0变为1,加一以后这些1变为0,相应的第一个1变回为1,比这个1高的位全是0,因为取反。最终就得到了一个只包含最右侧1的掩码,其余是0。这个方法是O1的。


第一题:https://leetcode.com/problems/single-number/?tab=Description

第一道题就是用了2,3性质直接得到的。使用交换律把相同的连续排放,最后xor结果是0,再和只出现一次的xor,得到本身。代码不贴了,很简单。


第二题:https://leetcode.com/problems/single-number-ii/?tab=Description

第二题是说有些数字出现了3次,有一个只出现一次。

其实是之前题目的延伸,可以使用位运算得到所有这列题目的规律,leetcode里面有。不过这里我觉得另一个思路很好很直观,也可以给出通解,只不过是O(32n)的。思路就是逐位相加,和取模,比如其余出现了k次,就模k,那么余数就是单独的那个数字在该位的二进制。

public int singleNumber(int[] nums) {
		int r = 0 ;
	 	for(int i = 0; i < 32; i++){
	 		int sum = 0;
	 		for(int j : nums){
	 			sum += (j >> i) & 1;
	 		}
	 		sum %= 3;
	 		r |= (sum << i);
	 	}  
	 	return r;
	}



第三题:https://leetcode.com/problems/single-number-iii/?tab=Description

是第一题的变种,一些出现两次,有两个数字a,b不同且各出现一次。先做一趟xor假设结果为x,那么x是a,b亦或的结果,因为二者不同那么x中必然有一位是1,我们使用方法4得到这个1,是一个只包含一位1的掩码。然后做第二趟xor,这次使用掩码分组操作。就可以区分a和b。其余额元素也会分组,不过不影响结果,因为肯定是在某一组中出现两次。

public int[] singleNumber(int[] nums) {
		int[] r = new int[2];
		int xor = 0;
	   	for(int i : nums){
	   		xor ^= i;
	   	}     
	   	xor &= (-xor);
	   	for(int i : nums){
	   		if((i & xor) == 0)
	   			r[0] ^= i;
	   		else
	   			r[1] ^= i;
	   	}
	   	return r;
	}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值