【leetcode】136. 只出现一次的数字-java

//	给定一个非空整数数组,
//   1)除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。稍微拓展下,
//   2)加深一步:有两个元素分别各出现一次,且两个元素一个是奇数,一个是偶数又该如何找到这两个数字。
//   3)更进一步:仅仅告诉你就是有两个数不同,且各出现一次,如何找出这两个数字
//	说明:
//	你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
//
//	示例 1:
//	输入: [2,2,1]
//	输出: 1
//	示例 2:
//
//	输入: [4,1,2,1,2]
//	输出: 4
//
//	来源:力扣(LeetCode)
//	链接:https://leetcode-cn.com/problems/single-number
//	著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

public class NumberOnce {

	public int singleNumber(int[] nums) {

		if (null == nums || nums.length == 0) {
			throw new IllegalArgumentException();
		}

		return singleNumber(nums, nums.length);

	}

	/**
	 * 从指定长度的数组里面找只出现一次的数
	 * 
	 * @param nums
	 * @param length
	 * @return
	 */
	private int singleNumber(int[] nums, int length) {
		int numOnce = nums[0];

		if (length == 1)
			return numOnce;

		// 采用异或操作
		for (int i = 1; i < length; i++) {
			numOnce = numOnce ^ nums[i];
		}

		return numOnce;

	}

	// 描述进一步,如果告诉输入里面有两个元素分别只出现一次,且两个元素一个奇数一个偶数,
	// 线下时间复杂度下能否找出这两个数字

	public int[] twoOddEvenNumber(int[] nums) {

		if (null == nums || nums.length < 2) {
			throw new IllegalArgumentException();
		}

		// 因为两个只出现一次的数分奇偶,所以可以按奇偶把元素重新分配
		int oddNum = 0;
		int evenNum = 0;

		for (int tem : nums) {
			// 偶数
			if (tem % 2 == 0) {
				evenNum = evenNum ^ tem;
			} else {
				oddNum = oddNum ^ tem;
			}
		}

		int[] retArr = new int[2];
		// i的值就是奇数数值的有效个数,j的值就是偶数数组的有效长度
		retArr[0] = oddNum;
		retArr[1] = evenNum;

		return retArr;

	}

	// 描述进一步,如果告诉输入里面有两个元素分别只出现一次,
	// 线下时间复杂度下能否找出这两个数字

	public int[] twoNumber(int[] nums) {

		if (null == nums || nums.length < 2) {
			throw new IllegalArgumentException();
		}

		int orNum = singleNumber(nums);// 找出两个不同数的异或结果
		int offset = 0;

		// 从低位开始找第一个为零的bit位,以此作为数组区分的依据,因为是int,所以最多循环32次
		for (int i = 0; i < 32; i++) {
			// 说明最低位是1,最低位不同
			if ((orNum ^ (orNum - 1)) == 1) {
				break;
			} else {
				orNum = orNum >> 1;
				offset++;
			}

		}

		int bitOne = 0;
		int bitZero = 0;

		for (int tem : nums) {
			// 先把tem左移 offset位赋值给临时变量m
			int m = tem >> offset;
			//把位为1的分组异或
			if ((m ^ (m - 1)) == 1) {
				bitOne = bitOne ^ tem;
			} else {
				bitZero = bitZero ^ tem;
			}

		}

		int[] retArr = new int[2];
		// i的值就是奇数数值的有效个数,j的值就是偶数数组的有效长度
		retArr[0] = bitOne;
		retArr[1] = bitZero;

		return retArr;

	}

	public static void main(String[] args) {

		int[] input = { 2, 2, 1, 1, 3,3,6, 4 };
		int[] out = new NumberOnce().twoNumber(input);
		 System.out.println(out[0]+","+out[1]);

		// System.out.println(10^9);


	}

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿凡提的哥

共享,共赢,共盈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值