문제 #
const array = [1,0,3,4];
-
위 배열은 길이가 4입니다.
-
예로 배열에 순서대로 값을 채워넣는 경우
[0, 1, 2, 3]
으로 이 때 빠진 값은 4입니다.- 0을 포함하기 때문에 배열의 길이와 빠진 수 없이 온전한 수열은 양립 할 수 없습니다.
-
위 배열에서 빠진 숫자는 2입니다.
해당 숫자를 O(n)의 시간복잡도와 O(1)의 공간복잡도를 사용해 빠진 숫자 2를 찾아봅시다.
bitwise operator - xor를 사용하는 방법 #
xor는 두개의 비트에 대해 서로 다를 경우 1, 같을 경우 0을 반환합니다.
1 ^ 0 = 1 // = 01 ^ 00 = 01
2 ^ 1 = 3 // = 10 ^ 01 = 11
xor는 결합법칙과 교환법칙이 성립합니다.
let x = 0;
let y = 1;
x ^ y = y ^ x; // 00 ^ 01 == 01 ^ 00
x ^ (x ^ y) = y ^ (x ^ x) // 01 ^ (00 ^ 00)
문제의 조금 더 디테일한 이해 #
문제는 한 숫자 배열을 입력으로 줍니다.
예를 들어 [1, 0, 3, 4]
를 배열로 주었을 때,
배열의 길이는 4입니다.
0 ~ 3까지의 배열을 순회하면서 총 가질 수 있는 숫자는 4개이므로
위 주어진 배열과 같이 2라는 값이 빠지게 됩니다.
이 때, 2를 반환하면 됩니다.
다시 예를 들면 [1, 2, 3]
이라는 배열은 배열의 길이가 3이고
0이라는 값이 빠졌으므로 0을 반환하면 됩니다.
배열의 길이와 같은 메모리를 사용해 체크하면 O(n)만큼의 시간, 공간 복잡도를 사용해 문제를 해결 할 수 있겠으나, O(n)의 시간복잡도와, O(1)의 공간복잡도를 사용해 문제를 해결해야 합니다.
계산된 값으로 보는게 아닌 변수의 전달 측면으로 본다면.. #
const array = [1, 0, 3, 4];
function findMissingNumberFrom(array) {
let xor = array.length;
for(let i = 0; i < array.length; i++) {
xor = xor ^ i ^ array[i];
}
return xor;
}
위 함수를 통해 이루어지는 반복문 안의 계산들을 나열해보겠습니다.
5 = 4 ^ 0 ^ 1
4 = 5 ^ 1 ^ 0
5 = 4 ^ 2 ^ 3
2 = 5 ^ 3 ^ 4
찾는 값 2
xor는 이전 값들의 결과를 계속 저장하는 역할을 합니다. 따라서 아래와 같이 나열해 볼 수 있습니다.
5 = 4 ^ 0 ^ 1
에서4 ^ 0 ^ 1
을 계산한 결과가 5입니다.- 따라서
4 ^ 0 ^ 1
을 가져옵니다. 4 = 5 ^ 1 ^ 0
에서 5는 이전 결과값이므로^ 1 ^ 0
을 가져옵니다.- 이 과정을 반복하면
xor = 4 ^ 0 ^ 1 ^ 1 ^ 0 ^ 2 ^ 3 ^ 3 ^ 4
이 됩니다.- 이를 계산해보면 2라는 값이 도출됩니다.
- 즉 xor를 초기화한 것은 이전 xor의 계산 결과를 다음 반복문에 넘겨주는 역할을 합니다.
이제 xor의 값 자체에 주목하는 것이 아닌 xor는 이전에 무슨 값이였고, 값을 다음 반복문에 넘겨주는 역할도 한다는 것을 알게 되었습니다.
위와 같은 xor 연산도 좋습니다만 다른 방법도 있습니다. 예를 들어 배열의 총 합을 구합니다. 배열은 0부터 n까지 정렬되어 있지 않은 수의 집합이고 그 중 하나의 수만 빠져 있습니다. 따라서 0부터 n까지의 합을 구하고 실제 반복문을 돌아 총 합에서 반복문을 돌아서 구한 합을 빼주면 나오는 차의 값이 배열에서 누락된 값입니다.
재미있는 xor을 활용한 변수 swap #
위 문제는 변수를 다음 반복문으로 넘기는 방법을 사용했습니다.
위와 관련해 하나 더 재미있는 xor operator를 이용해 변수간 값의 swap이 가능합니다.
let a = 1;
let b = 2;
a = a ^ b;
b = a ^ b; // b ^ (a ^ b) == b ^ (b ^ a) == a 이제, b == a
a = a ^ b; // a ^ b ^ a == a ^ a ^ b == 0 ^ b == b 이제, a == b
a // 2
b // 1
놀랍게도 스왑이 이루어졌습니다.
bitwise operator의 숨은 장점은 잘 사용하는 경우 코딩을 정말 잘해보이는 효과가 있습니다. 🤣