Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 두 개의 방정식으로 반복 숫자와 누락된 숫자 찾기

문제 소개

크기가 N인 배열 arr[]이 주어집니다. 배열에는 1부터 N까지의 정수가 담겨 있지만, 그중 한 숫자 x는 빠져 있고(누락), 대신 다른 숫자 y 하나가 두 번 등장합니다(반복). 이 글에서는 두 개의 방정식을 활용해 반복되는 숫자와 누락된 숫자를 찾는 방법을 알아보겠습니다.

예제를 통해 문제를 살펴보겠습니다.

입력

arr[] = {1, 2, 3, 3}

출력

누락된 숫자 = 4, 반복 숫자 = 3

해결 접근 방식: 두 개의 방정식 세우기

핵심 아이디어는 간단합니다. 누락된 값 x와 반복 값 y에 관한 두 개의 방정식을 만든 뒤, 이를 연립해 풀면 됩니다.

첫 번째 방정식: 합 이용하기

배열 원소 전체의 합(arrSum)은 '1부터 N까지 자연수의 합'에서 누락된 x가 빠지고, 대신 y가 한 번 더 포함된 값입니다.

arrSum = Sum(N) - x + y
y - x = arrSum - Sum(N)

이것이 첫 번째 방정식입니다.

두 번째 방정식: 제곱합 이용하기

같은 논리를 제곱합에 적용하면 다음과 같습니다.

arrSumsq = sqSum(N) - x2 + y2
(y - x)(y + x) = arrSumsq - sqSum(N)

여기에 첫 번째 방정식에서 구한 (y - x) 값을 대입하면,

x + y = (arrSumsq - sqSum(N)) / (arrSum - Sum(N))

x와 y 구하기

이제 두 식을 더하거나 빼면 각각 y와 x를 구할 수 있습니다.

y = { (arrSumsq - sqSum(N)) / (arrSum - Sum(N)) + (arrSum - Sum(N)) } / 2
x = y - (arrSum - Sum(N))

참고로 1부터 N까지의 합과 제곱합은 다음 공식으로 바로 계산할 수 있습니다.

Sum(N) = N × (N + 1) / 2
sqSum(N) = N × (N + 1) × (2N + 1) / 6

여기서 arrSum은 배열 모든 원소의 합, arrSumsq는 배열 모든 원소 제곱의 합입니다.

C++ 구현 예제

다음 프로그램은 위 접근 방식이 실제로 동작하는 모습을 보여줍니다.

#include <iostream>
using namespace std;

void findMissingAndRepeatingVal(int arr[], int n) {
    // 오버플로 방지를 위해 long long 사용
    long long sumN = (long long)n * (n + 1) / 2;
    long long sqSumN = (long long)n * (n + 1) * (2 * n + 1) / 6;

    long long arrSum = 0, arrSqSum = 0;
    for (int i = 0; i < n; i++) {
        arrSum += arr[i];
        arrSqSum += (long long)arr[i] * arr[i];
    }

    long long diff = arrSum - sumN; // y - x
    long long sumXY = (arrSqSum - sqSumN) / diff; // y + x

    long long y = (diff + sumXY) / 2; // 반복 숫자
    long long x = y - diff; // 누락된 숫자

    cout << "배열에서 누락된 값: " << x << endl;
    cout << "배열에서 두 번 나타나는 값: " << y << endl;
}

int main() {
    int arr[] = { 1, 2, 2, 3, 4 };
    int n = sizeof(arr) / sizeof(arr[0]);
    findMissingAndRepeatingVal(arr, n);
    return 0;
}

출력 결과

배열에서 누락된 값: 5
배열에서 두 번 나타나는 값: 2

배열 {1, 2, 2, 3, 4}에는 1부터 5까지의 숫자 중 5가 빠져 있고, 2가 두 번 등장하므로 올바른 결과입니다.

복잡도 분석

시간 복잡도: O(N) — 배열을 한 번만 순회하면 됩니다.
공간 복잡도: O(1) — 입력 크기와 무관한 상수 공간만 사용합니다.

마무리

합과 제곱합이라는 두 개의 방정식만 세우면, 별도의 추가 배열이나 정렬 없이도 반복 숫자와 누락된 숫자를 선형 시간에 구할 수 있습니다. 다만 N이 매우 클 경우 합의 값이 커질 수 있으므로, 위 예제처럼 long long 같은 넉넉한 자료형을 사용하는 것이 안전합니다.