这是一道简单的题目,但是想真正做好,还是挺有意思的。
题目 链接:https://leetcode-cn.com/problems/single-number
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
输入输出示例:
输入: [2,2,1]
输出: 1
一眼看去先忽略了最后一句 " 不使用额外空间 "
从头到尾遍历一遍
class Solution {
public int singleNumber(int[] nums) {
ArrayList<Integer> element = new ArrayList<Integer>();
for(int x: nums){
if(!element.contains(x)){
element.add(x);
}else{
element.remove(new Integer(x));
}
}
return element.get(0);
}
}
一顿操作猛如虎,轻易通过提交,一看方案排名傻了眼。
刷题的大佬们的方案都是更优的方案。就让我们来寻找一下更优的方案吧。
方案一
改用 hashset, 因为hashset的查找比起arraylist更加快速。
具体的试验看此链接
class Solution {
public int singleNumber(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for (int n : nums) {
if (!set.contains(n)) {
set.add(n);
} else {
set.remove(n);
}
}
for (int n : set) {
return n;
}
return 0;
}
}
方案一可以进一步改进为以下方式,减少对set的操作。
class Solution {
public int singleNumber(int[] nums) {
int sumOfSet = 0, sumOfNums = 0;
Set<Integer> set = new HashSet();
for (int num : nums) {
if (!set.contains(num)) {
set.add(num);
sumOfSet += num;
}
sumOfNums += num;
}
return 2 * sumOfSet - sumOfNums;
}
}
方案二
我们可以对原数组进行排序,对原来的数组进行排序。然后对比相邻的两个数字
class Solution {
public int singleNumber(int[] nums) {
Arrays.sort(nums);
int i = 0;
while (i < nums.length) {
if(i==nums.length-1) return nums[i]; // 比较完毕到最后一个数字还没找到
if(nums[i]!=nums[i+1]){
return nums[i];
}
i = i + 2;
}
return 0;
}
}
最佳方案
使用 位运算
https://www.runoob.com/java/java-operators.html
举例: A = 0011 1100 B = 0000 1101
举例 | 符号 | 意义 |
---|---|---|
A&B = 0000 1100 | & | 如果相对应位都是1,则结果为1,否则为0 |
A | B = 0011 1101 | | | 如果相对应位都是 0,则结果为 0,否则为 1 |
A ^ B = 0011 0001 | ^ | 如果相对应位值相同,则结果为0,否则为1 |
~A= 1100 0011 | 〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 |
A << 2得到240,即 1111 0000 | << | 按位左移运算符。左操作数按位左移右操作数指定的位数。 |
A >> 2得到15即 1111 | >> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 |
A>>>2得到15即0000 1111 | >>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 |
由于题目中所说,两两相同,只有一个数字不同,所以会有两两数字在 ^ 操作后变成 0000000…
最终会有 2n 个数字互相抵消变成 0000… 最后只剩下格格不入的答案。
class Solution {
public int singleNumber(int[] nums) {
int num=nums[0];
for(int i=1;i<nums.length;i++){
num=num^nums[i];
}
return num;
}
}