1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| Consider the number:
[1(0), 1(1), 2(2), 3(3), 3(4), 4(5), 4(6), 8(7), 8(8)]
, number(index)
Here, the single number is 2, let's call it SN
Note that:
- For each duplicate pair that appears to the left
of SN, the first occurence appears at even index
and second occurence appears at odd index
- For each duplicate pair that appears to the right
of SN, the first occurence appears at odd index
and second occurence appears at even index
Now to easily detect weather we are to the left or
right of SN, we can employ XOR with 1 operator.
Property of XOR with 1 operator:
XOR_1(x) = x ^ 1 = x + 1 , when x is even
XOR_1(x) = x ^ 1 = x - 1 , when x is odd
From this knowledge, it can be infered that for each index i:
number[ i ] = number[ XOR_1(i) ] ,when i is to
left of SN
number[ i ] != number[ XOR_1(i) ] ,when i is at SN or to
the right of SN
For example, at i=1, i is to left of SN
number[i] = number[1] = 1 == number[ XOR_1(1) ]
= number[ 1-1 ] = number[0] = 1
at i=2, i is at Single Number (SN)
number[2] = 2 != number[XOR_1(2)] = number[3] = 3
at i=6, i is to right of SN
number[6] = 4 != number[XOR_1(6)] = number[7] = 8
You can verify this for any i
Now our job is to find the minimum valud of i such that
number[i] != number[XOR_1(i)]
This can be done using binary search.
It is worth mentioning that at i=8 in the above example
number[ XOR_1(8) ] = number[ 9 ] which is out of bonds
We avoid this situation by using ( i < j ) as loop
condition. Which implies that i will never reach the
end to make mid = 9
The binary search is designed such that j always takes
valid values, where valid means nums[j] != nums[j^1]
When i == j, we are at the leftmost valid index, which
is exactly what we require
|