前言
最近偶然听说LeetCode 这个网站有大把的编程题,按捺不住自己想要被虐的冲动,决定写下这个专栏,分享一些题目的最佳解题思路,当然解题思路可能是借鉴别人的,我只是记录下自己的心得,共勉!
题目赏析
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
要求:
不使用额外的存储空间
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
解题思路
1)不考虑题目的要求,使用集合工具类来解题
- 建立一个 HashSet 集合
- 遍历传入的数组,如果在集合中不存在当前遍历的数据,就存进集合中,如果发现相同的数据就移除原先进入集合的数据
- 最终集合中剩下的数据,就是我们需要的结果
- 如果集合为空,则说明该数组中全是重复的数据或者重复的次数全是两次,暂时不考虑数据重复次数为奇数次的情况
示例代码
// 请忽略掉函数名字
public static int getSingleNumber(int[] arr) {
if(arr.length == 0) { // 数组不能为空 这里我随意抛了个异常
throw new RuntimeException("数组不能为空");
}
// 新建一个HashSet 集合 用于存储我们需要的结果
Set<Integer> singleSet = new HashSet<>();
// 遍历数组
for(int i=0;i<arr.length;i++) {
// 如果集合包含该元素 就移除当前元素 (也就是说重复了就把数据移出容器)
if(singleSet.contains(arr[i])) {
singleSet.remove(arr[i]);
// 移除重复数据后 继续执行循环
continue;
}
// 如果不包含该元素就放入到set集合中
singleSet.add(arr[i]);
}
// 根据题意最终只会存在一个单独的数据 所以使用迭代器取出数据即可
return singleSet.iterator().next();
}
测试用例和结果
int[] arr = {2,3,4,4,2,3,1};
获取得数组中的唯一数据为:1
为什么选用HashSet 集合你们可以思考一下下哦!
2)考虑题目要求不适用额外的存储空间
首先我们需要复习一下知识点,^ 这个位操作符大家应该都熟悉吧,0 0 变 0, 1 1 变 0,0 1 变 1, 1 0 变 1, 魔术戏法谁用谁知道
接下来让我们来分析一下 ^ (异或操作符)的一个重要的特性
假设:a = 10 其二进制表示为 1010 (为了方便分析我们只取低四位), b = 5 二进制为 0101
现在我们有一个中间变量 c。
1) c = a ^ b = 1010 ^ 0101 = 1111;
2) c ^ b = 1111 ^ 0101 = 1010 --> 最终结果 == a.
从上面的例子可以看出,一个数同另一个数异或两次,会得到其本身。
我们可以将这个特性代入题目中,可以看到题目中数组内部重复的数刚好是两个,至此天时地利人和完备了,解题思路飞出来了,不说了上代码:
/** 惊不惊喜?意不意外?这就是编程的魅力,这么简单几句代码就可以解决一个问题,足够优雅
public static int singleNumber(int[] nums) {
// 初始化最终结果 ,假定第一个数是最终结果
int result = nums[0];
// 遍历数组 无限异或直到遍历完毕
for(int i = 1;i<nums.length;i++){
result ^= nums[i];
}
// 异或特性 重复的全部消除
return result;
}
用例就不上了,肯定对的,这是官方公认的最佳解决方案,确实厉害呀!而且使用位操作符最大化了计算机的计算能力,努力学习吧,路还很长鸭!