개발공부/LeetCode

[LeetCode] 1442. Count Triplets That Can Form Two Arrays of Equal XOR

장아장 2024. 5. 30. 15:40

https://leetcode.com/problems/count-triplets-that-can-form-two-arrays-of-equal-xor/description/?envType=daily-question&envId=2024-05-30

문제 출처

 

비트연산자, 그 중에서도 XOR의 특성을 알면 쉽게 풀 수 있는 문제였다. 

요즘 리트코드 데일리 문제를 하나씩 푸는 재미에 꽂혔다. 

작년 이맘 때 즈음엔 비트연산자 문제가 나오면 스트레스를 받았는데, 

요즘엔 오히려 비트연산자가 더 재미있다는 느낌을 받았다. 

 

이 문제를 이해한 바로는 아래와 같다. 

 

  • 전체 배열에서 시작 인덱스 i, 끝 인덱스 j를 정한다. 
  • 그리고 그 끝 인덱스의 다음인 j+1에서, 또다른 끝 인덱스 k를 정한다.
  • 이 때 i부터 j까지 XOR한 값과 j+1부터 k까지 XOR한 값이 같을 경우 그 경우를 센다. 
  • 그렇게 센 모든 경우의 수를 반환한다. 

이걸 풀기 위한 접근은 XOR의 특성을 가지고 설명해야 한다. 

 


XOR를 이용한 아이디어 구상하기

XOR 연산은 두 비트가 다르면 1, 같으면 0을 반환한다. 

즉, 아래와 같은 기본 식이 성립된다. 

x ^ x = 0, x ^ 0 = x

 

그렇다면 i~j까지를 a라고, j+1부터 k까지를 b라고 한다면, a ^ b는 어떻게 될까?

 

i~(j-1) = a, j~k = b일 때, a ^ b = 0

이러한 식이 성립한다. 

 

즉, 우리가 세어야 할 경우의 수는 다음과 같다. 

i^(i+1)^...^k = 0인 i와 k를 구하고 그 속에서 j

 

여기까지 x ^ x = 0이라는 식 하나만을 가지고 만들 수 있는 아이디어였다. 

이제 x ^ 0 = x를 같이 이용해 아이디어를 계속 해나갈 것이다. 

 

i~k를 XOR한 값은 아까 말했듯이 0이어야 한다. from 부터 to 까지 XOR한 값을 XOR(from, to)라고 하겠다. 

 

이전의 x ^ 0 = x라는 식과, x ^ x = 0이라는 두 식을 이용할 것이다. 

XOR(from, to)  = 0

이런 식에서 양쪽에 from을 XOR해주자. 

XOR(from, to) ^ from  = 0 ^ from = from

여기에서 왼 쪽에는 이미 from이 XOR연산으로 추가되어있다. 그렇기에 x ^ x = 0으로 소거된다. 

그렇게 식은 다음과 같이 바뀐다. 

 

XOR(from + 1 , to) = from

그런데, 아무것도 없는 상태에서 from인덱스의 값만을 XOR해주어도 from이 나온다. 

그 다음 경우를 생각해볼까?

XOR(from + 1 , to) ^ (from+1) = from ^ (from+1)
XOR(from + 2, to) = XOR(from, from+1)

이렇게 계산할 수 있다. 이전의 소거와 추가를 생각하면 된다. 

 

그렇기에 도달할 수 있는 결론이 생긴다. 

j는 셀 필요 없다. XOR(i, j)에서 j의 범위만 구해주면 된다.

 

위의 조건에서 보면 i < j <= k라고 되어있다. 

즉, i와 k의 범위를 안다면, k - i를 해주면 그게 해당 범위 내에 존재하는 Triplets이 된다. 


코드로 만들기(JAVA)

i의 범위는 조건을 보았을 때, arr.length-1로 잡아주면 된다. 

왜냐하면 조건상 k도 arr.length보다 작아야 하는데, i < k기 때문이다. 

 

k는 i+1부터 arr.length보다 작은 동안 반복시켜주면 된다. 그 동안 하나씩 XOR해주면 된다. 

i부터 하나씩 XOR할 때, XOR한 값이 0이면 그 때 마다 k - i를 구해 누적해주면 된다. 

 

public int countTriplets(int[] arr) {
    int count = 0;
    for(int from = 0; from < arr.length-1; from++) {
        int xorValue = arr[from];
        for(int to = from+1; to < arr.length; to++) {
            xorValue ^= arr[to];
            if(xorValue == 0) {
                count += to - from;
            }
        }
    }
    return count;
}

그렇게 이런 답을 만들었다. 

 

 

 

그럼...twenty thousand...🔥