头图

1. Background

I recently came across an algorithm problem: find a number that appears only once in an array.

The title description is this:

Given a non-empty array of integers, each element appears twice except one that appears only once. Find the element that appears only once

Explanation: Your algorithm should have linear time complexity. Can you do it without using extra space ?

Example:

Input: [4, 1, 2, 2, 1]

output: 4

Without reading the description, the smart mind immediately thought of using the object to store the number that has appeared in the array, and then the number appears again delete the number, and finally there is only one number left in the object. This is also one of the ways to solve problems with violence.

Talk is cheap, Show me your code:

 /**
 * @param {number[]} nums
 * @return {number}
 */
const singleNumber = function(nums) {
  const result = {};
  for (let i = 0; i < nums.length; i++) {
    if (result[nums[i]] === undefined) {
      result[nums[i]] = nums[i];
    } else {
      delete result[nums[i]];
    }
  }
  return Object.values(result)[0];
};

The problem is solved, but the performance is mediocre:

对象存储.png

On second thought, the quickest way, without using extra space, is to sort the array first, and then compare adjacent numbers for equality . Is it a clever one, and quickly put the code:

 /**
 * @param {number[]} nums
 * @return {number}
 */
const singleNumber = function(nums) {
  const newNums = nums.sort();
  let num = newNums[0];
  if (newNums.length === 1) {
      return num;
  }
  for(let i = 0; i < newNums.length; i++) {
      if (newNums[i] !== newNums[i + 1]) {
        if (i === 0) {
            num = newNums[0];
            break;
        }
        // 可前置判断是否数组越界
        // if (i + 3 > newNums.length) {
        //     num = newNums[i + 1];
        //     break;
        // }
        if (newNums[i + 1] !== newNums[i + 2]) {
            num = newNums[i + 1];
            break;
        }
      }
  }
  return num;
};

As expected, the problem is solved and the performance is improved:

优化后的2.png

Do you suddenly feel that you can do it again! !

Just when I thought I could hand in my homework in this way, I looked at other students' problem-solving ideas, and I realized that I am really smart. There is a mathematical operator that solves every second: XOR

Code first:

 /**
 * @param {number[]} nums
 * @return {number}
 */
const singleNumber = function(nums) {
  return nums.reduce((a, b) => a ^ b, 0);
};

You read that right, just one line of code! ! ! ! More amazing is yet to come, let's see how the performance is:

异或运算2.png

Sure enough, the lack of knowledge limits my imagination. Of course, there are more powerful problem-solving methods. You are also welcome to communicate in the comment area. Then I will introduce the XOR operation to you.

2. Introduction

The logical operations that everyone is familiar with are mainly "AND" ( AND ) and "OR" ( OR ), and there is also an "XOR" ( XOR ) is also very important.

XOR is the abbreviation of exclusive OR , which is mainly used to judge whether two values are equal.

XOR Generally use the caret ( caret ) ^ to indicate. If 0 is false and 1 is true , then the truth table of XOR is as follows:

 0 ^ 0 = 0;
0 ^ 1 = 1;
1 ^ 0 = 1;
1 ^ 1 = 0;

2.1 The Law of Operation

  • A value and itself, always false

     x ^ x = 0;
  • A value is computed with 0 , which is always itself

     x ^ 0 = x;
  • interchangeability

     x ^ y = y ^ x;
  • associative

     x ^ (y ^ z) = (x ^ y) ^ z;

3. Application

According to the above operation laws, many important applications of XOR operation can be obtained.

3.1 Simplified operations

The XOR operation of multiple values can be simplified according to the operation law:

 a ^ b  ^ c ^ a ^ b
= a ^ a ^ b ^ b ^ c
= 0 ^ 0 ^ c
= c

3.2 Interaction value

Two variables are XORed three times in a row, and they can exchange values with each other.

 let a = 1;
let b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(`a: ${a}, b: ${b}`); // a: 2, b: 1

This is the fastest way to swap values between two variables and doesn't require any extra space. It is also the key to solving the problem at the beginning to find the number that only appears once in the array.

3.3 Encryption

XOR operation can be used for encryption.

The first step, plaintext: text and key: key XOR operation, you can get ciphertext: cipherText

 text ^ key = cipherText;

In the second step, the ciphertext and the key are XORed again to restore the plaintext

 cipherText ^ key = text

The principle is very simple, if the plaintext is x and the key is y , then x consecutively OR with y twice in a row get yourself.

 (x ^ y) ^ y
= x ^ (y ^ y)
= x ^ 0
= x

3.4 Data Backup

XOR operation can be used for data backup.

The file x and the file y are XORed to produce a backup file.

 x ^ y = z

Later, whether file x or file y is damaged, as long as the two original files are not damaged at the same time, the restoration can be performed based on the other file and the backup file.

 x ^ z
= x ^ (x ^ y) 
= (x ^ x) ^ y
= 0 ^ y
= y

The above example is y corrupt, x and z XOR, you can get y .

4. Conclusion

If a worker wants to do a good job, he must first sharpen his tools. Only by constantly improving your own knowledge system can you discover a different world, respect! !

5. Reference links

That XOR Trick


Clearlove
1.2k 声望53 粉丝

专注做好一件事