알고리즘 문제를 풀던 중 해괴한 연산자를 만나버렸다.
XOR(^
) 이라는 연산자였는데, 사실 이게 연산자라는 것도 예시를 보고 알았다 듣도 보도 못해본 연산자니까 일단 냅다 MDN 검색 ㄱㄱ
MDN 비트 XOR(^) 연산자 문서를 보면 알겠지만, 설명이 몹시 불친절하다.
설명에 의하면, XOR 연산자는 각 비트 쌍을 대상으로 연산을 수행한다. a ^ b 는 a와 b가 다르면 1을 리턴하고, 같으면 0을 리턴한다.
이쯤에서 문제를 확인해보자.
문제
There is a hidden integer array
arr
that consists ofn
non-negative integers.
It was encoded into another integer arrayencoded
of lengthn - 1
, such thatencoded[i] = arr[i] XOR arr[i + 1]
. For example, ifarr = [1,0,2,1]
, thenencoded = [1,2,3]
.
You are given theencoded
array. You are also given an integerfirst
, that is the first element of arr, i.e.arr[0]
.
Return the original arrayarr
. It can be proved that the answer exists and is unique.
대강 내용은 이렇다.
만들어야 할 함수의 인자는 2개다.
1. encoding된 배열encoded
2. encoding되기 전 원본 배열인arr
의 첫번째 엘리먼트first
이 때,encoded
의 i번째 인덱스에 해당하는 엘리먼트는arr[i] XOR arr[i + 1]
이다.
따라서 당연히encoded
의 길이는arr.length - 1
이 된다.
우리는encoded
와 원본배열의 첫번째 엘리먼트인first
를 받아서 원본 배열인arr
를 반환하는 함수를 만들어야 한다.
여기서 의문.
분명히 MDN에서는 "XOR 연산자는 각 비트 쌍을 대상으로 연산을 수행한다. a ^ b 는 a와 b가 다르면 1을 리턴하고, 같으면 0을 리턴한다." 라고 했는데 XOR 연산을 거친 결과값에 1이나 0이 아닌 수가 등장한다.
보통 연산이라는게 a * b = c
라면 a = c / b
인 것처럼 가는게 있으면 오는게 있는 법이니까.. 그렇다면 XOR 연산자도 반대 연산자가 있을까 검색해보았지만 나오지 않았다.
그래서 시작된 나의 뻘짓...
(혹시 이 글을 읽게될 누군가가 있다면, XOR 연산자에 대한 진짜 정보는 여기쯤은 되어야 나온다는 것을 미리 밝힙니다.)
XOR 연산자의 규칙을 찾겠다는 황당하고 무모한 시도를 시작했다.
뻘짓의향연.jpg
encoded[i]
는 짝수고 arr[i]
은 홀수인 경우만 제외하면 규칙을 찾았다고 생각했지만 오산이었다.
var decode = function(encoded, first) {
let arr = [first];
encoded.reduce((acc, curr) => {
if (curr % 2 === 0 && acc % 2 !== 0) {
arr.push( Math.abs(acc - curr) );
return Math.abs(acc - curr);
} else {
arr.push(Math.abs(curr - acc));
return Math.abs(curr - acc);
}
}, first);
return arr;
};
내가 생각한 규칙에 따르면,
encoded = [1, 2, 5, 2, 4]
, first = 1
을 받았을 때 결과값으로 [1, 0, 2, 3, 5, 1]
이 반환되어야 한다. 하지만 정작 반환된 값은 [1, 0, 2, 3, 1, 3]
였다. 내가 만든 테스트케이스가 잘못되었나 싶어서 일단 실행시켜봤다.
실행결과001.jpg
문제는 encoded[i]
는 짝수고 arr[i]
은 홀수인 경우가 아니었다. 그냥 내가 생각한 룰 자체가 잘못됐던 것. 그래서 다시 원점으로 돌아가 되는대로 뒤지다가 진짜 룰을 발견했다.
뻘짓의향연AndFinally.jpg
맨 아래쪽을 보면 5 ^ 3
의 결과가 6
이 나온 것이 보인다. 그 다음 줄에 보면 3 ^ 5
의 결과도 6
이 나왔다. 뺄셈의 절댓값도 아니고 도대체 무슨 규칙일까 고민하다가 시도해본 3 ^ 6
. 놀랍게도 결과는 5
였다. (설마 니들 듀오가 아니라 트리오였니..?)
바로 5 ^ 6
을 확인해보니 3
이 나온다. YEAHHHHHH!!!!!!
그 후로 이것 저것 테스트 케이스를 더 돌려보고 트리오라는 확신을 얻고나자 그제서야 보이는 문제의 그 단어, encoded.
암호와 키와 원본은 당연히 한 쌍으로 움직여야 한다는 걸 놓친 것부터 잘못된거였다...
Anyway, 내가 알아낸 XOR 연산자의 규칙은 다음과 같다.
let a = 5;
let b = 3;
// a와 b는 임의의 정수 아무거나 상관없다.
const result = a ^ b; // --> 5 ^ 3 === 6
console.log(b ^ a); // --> 6
console.log(a ^ result); // --> 3
console.log(result ^ a); // --> 3
console.log(b ^ result); // --> 5
console.log(result ^ b); // --> 5
a XOR b
의 결과가 c
일 때, (a
, b
, c
)가 한 쌍이라고 보면 된다. 셋 중 아무거나 두개를 골라 XOR 연산을 실행하면 결과는 나머지 하나가 나온다.
이 규칙을 알고나면 문제는 반복문을 통해 간단하게 해결할 수 있다. 혹시 나중에 이 글을 읽게 될 수도 있으니 정답은 생략하겠다. (새로 풀어보자!!)
실행결과-최종.jpg
힘겹게 알아낸 규칙이라서 정리해두려다가 뻘짓의 향연이 진짜 '뻘짓' 은 아니었다는 생각에 그 과정을 주절거려봤다. 역시 시행착오를 겪으면서 해결방법을 찾아내는게 코딩의 매력인 것 같다.
-끝-
모든 케이스를 확인해보고 검증을 완료한 규칙이 아니기 때문에 잘못된 부분이 있을 수 있습니다. 오류를 발견하셨다면 댓글로 알려주시면 감사하겠습니다. 🙇♀️
안녕하세요 위의 경우를 설명드리면
5 -> 101
3 -> 011
6 -> 110
5 xor 3
101
011
= 110 (6, 같은 자리수가 둘 다 1일 경우 0으로 바뀌는 것입니다.)
6 xor 5
110
101
= 011 (3)
6 xor 3
110
011
= 101 (5)
같은 자리수가 둘 다 1일 경우 0으로 바뀌는 것이기 때문에 숫자의 순서는 상관이 없습니다!
그리고 반대의 연산자는 xand 연산자라고 할 수 있을 것 같네요!
그리고 2 ^ 2 = 4라고 되어있는데 이건 xor 연산자로 작용한 게 아니라 ^(승) 연산자로 적용된 것 같습니다! 아마 그래서 좀 더 헷갈리셨을 것 같습니다!
안녕하세요? 잘 읽었습니다!
xor 는 비트연산자로 계산하는것 으로 알고 있습니다. 규칙이라면 참고하실 수 있을 것 같습니다.
예)
2 = 10
3 = 11
2^3의 경우
2의 1승 자리 = 0
2의 0승 자리 = 1
2^3 = 1 (이진법 01)