C# 프로그래밍 기초 실습 전자책

C# / .NET 알고리즘과 퀴즈
본 알고리즘 퀴즈 문제는 C#/.NET 개발자를 위한 알고리즘 인터뷰 혹은 C# 프로그래밍을 통한
문제 해결 알고리즘을 연구해 보는데 도움이 되고자 작성되었습니다.


퀴즈 질문


예상답변/설명

우선 하나의 해법으로 모든 배열 요소의 합을 구한 후, 1부터 백만까지의 숫자를 모두 더한 값을 수학적으로 구하여 이를 빼면 무엇이 하나 더 들어 있는지를 알 수 있다. 수학적으로 1부터 N까지의 합은 N * (N+1) / 2 공식을 통해 구할 수 있다.

int SumMethod(int[] A) 
{            
    int sum = 0;
    for (int i = 0; i < A.Length; i++)
    {
        sum += A[i];
    }

    int n = A.Length - 1;
    int expectedSum = n * (n + 1) / 2;

    return sum - expectedSum;
}

하지만, 이러한 해법은 한가지 치명적인 문제가 있는데, 만약 배열이 100만이 아니라 1000만이 된다면, Overflow가 발생한다는 것이다. 물론 이 경우 sum 타입을 int가 long으로 하면 일시적으로 해결할 수는 있지만, 또다시 입력 숫자가 커진다면 계속 문제가 발생할 수 있다.

Overflow가 발생하지 않는 다른 해법으로 XOR를 사용하는 방식을 생각해 볼 수 있다.

int XorMethod(int[] A)
{
    int r = 0;
    for (int i = 0; i < A.Length; i++)
    {
        r = r ^ A[i] ^ i;
    }
    return r;
}

XOR는 동일한 숫자를 XOR하면 0가 되는 성질이 있다. 따라서, 1부터 100만까지의 루프를 돌면서 for 루프의 i와 배열 A[i]를 XOR하면 1부터 100만까지의 동일한 숫자는 0가 되고 중복된 숫자만 하나 남게 된다. 예를 들어, 배열에 1부터 10까지 들어 있고 하나면 중복된 숫자가 들어 있다면, 아래와 같이 들어 있다고 볼 수 있다. (물론 실제 A[i]는 순서는 소트되지 않고 랜덤하게 있겠지만 XOR 연산에서 이는 중요하지 않다)

 i  :   0   1   2   3   4   5   6  7  8  9  10 
A[i]:   1   2   3   3   4   5   6  7  8  9  10

i의 1과 A[0]의 1은 서로 상쇄되고, i=2와 A[1]=2는 서로 상쇄된다. 이런 식으로 지우다 보면, 중복값 A[3]=3과 i=0만 남게 되는데 이를 XOR하면 중복값 3을 구할 수 있다.