Description:
Example 1:
Example 2:
Note:
Solution1 (C++):
Solution2 (C++):
Solution3 (C++):
算法分析:
解法一:这一道题的解法我参考了之前的一道题的方法。LeetCode-448. Find All Numbers Disappeared in an Array。
因为之所以想到这个方法是因为首先都是要找到数组里消失的元素,然后要找到数组里的元素的变化范围都在0~n之内。所以我尝试在数组内部通过变换找到消失的元素。其实解法不难。但我还是有两个地方卡了一下:
- 由于数组元素最大可到达n,而数组索引最大值为n-1,所以必须事先判断将数组元素的值作为索引重新传入数组的时候,判读元素的值会不会超过索引最大值。
- 由于我是通过将数组的元素取反的方法来判断,对应的元素的索引有没有访问过。而最头疼的一个地方就是0,可以分为两种情况,当0所在的位置有元素对应,那么,假如i=6,nums[6]=0,这时应该让i=6对应的元素值取负数,表示6这个元素存在,然而这时i=6对应的是0,0取负数还是0,而当0所在的位置正好缺少那个元素对应的数,比如说数列:[1,2,0],那么这个时候,0应该不会取反,如果换成其他数,就会是正数,然后被后面的一遍遍历查找出来,然而这是0.所以0就很头疼。
为了解决这个问题,我才有了第一遍遍历都将数列中的元素+1.
解法二:这个就是借用了数学思维了。很简单,将应该完整的数列全部加起来,然后减去实际的数列中所有元素的和,就能得到缺少的元素了。很简单,但是解法二能对解法三的理解起到一定的帮助。
解法三:这个方法更加普遍。关键在于异或的使用。其实这个思路也很简单,充分利用了异或运算符的特点。那就是a^b^b=a。为什么?因为b^b=0,而a^0=a。所以,这个题目我们可以首先把0~n全部异或一遍。然后将结果与数列中的元素全部异或以便。对于数列中应有的元素,会异或两次,而消失的那个元素,只会异或一次。那么这样全部运算的结果就自然是消失的元素了。可以证明如下:
//设a0,a1,a2,a3,...,an就是0,1,2,3,...,n;
//数列缺少元素ai;
//第一次异或结果为:
int res1=a0^a1^a2^a3^...^ai^...^an;
//然后与数列中元素进行异或:
int res2=res1^a0^a1^a2^...^ai-1^ai+1^...^an
=a0^a1^a2^a3^...^ai-1^ai^ai+1...^an^
a0^a1^a2^a3^...^ai-1^ ^ai+1...^an
=0 ^0 ^0 ^0 ^...^0 ^ai^0 ...^0
=ai.
//证明完毕。
程序分析:
程序中要注意的地方就是这里使用了新的for遍历vector的方法:
for(int num:nums){
//......num每次循环会自动赋为i=0,1,2,...,n-1对于的元素值
}
然后就是异或运算符^,常用运算公式有:
- 0^0=0,1^1=0;
- 0^1=1,1^0=1;
- a^0=a,a^1=~a;
- a^a=0,a^~a=1;
- a^b=b^a;
- a^b^c=a^c^b;
- a^b^b=a^0=a;