算法:寻找异常数字
Contents
题目描述:
寻找异常数字。 输入一个无序的公差为1的等差数列,其中有一个数不属于此数列,找到这个数。
举例: 输入1 3 2 3 , 输出为3 输入2 5 3 7 4,输出7
解法1:暴力解法
通过从头到尾遍历数组,找到异常的数字。
int GetExceptionalNumber(int arr[], int n)
{
    if (arr == nullptr || n < 3)
    {
        return -1;
    }
    QuickSort(arr, n);
    for (int i = 1; i < n; ++i)
    {
        if (arr[i] - arr[i-1] == 1)
        {
            continue;
        }
        if (i < n-1)
        {
            if (arr[i+1] - arr[i] == 1)
            {
                return arr[i-1];
            }
            else
            {
                return arr[i];
            }
        }
        else // (i-1) != 0
        {
            if (arr[i-1] - arr[i-2] == 1)
            {
                return arr[i];
            }
            else
            {
                return arr[i-1];
            }
        }
    }
    return -1; // not found
}
解法二:二分法
使用二分查找的方法,这里的关键是怎么确定目标数字。这里有两个关键点:1.数组的公差为1 ;2.排序后,数组是有序的。 如此,可通过判断数字与数字的下标是否相等。

int GetExceptionalNumber(int arr[], int n)
{
    if (arr == nullptr || n < 3)
    {
        return -1;
    }
    QuickSort(arr, n);
    // 判断第一个为异常数
    if (arr[1] - arr[0] != 1)
    {
        if (arr[2] - arr[1] == 1)
        {
            return arr[0];
        }
    }
    int startNumber = arr[0];
    int l = 0;
    int r = n - 1;
    while (l <= r)
    {
        int midIndex = l + (r-l)/2;
        if (l == r)
        {
            return arr[midIndex];
        }
        int midNumber = midIndex+startNumber;
        if (midNumber > arr[midIndex])
        {
            r = midIndex-1;
        }
        else // midNumber == arr[midIndex]
        {
            if (midIndex < n-1 && arr[midIndex+1] == arr[midIndex])
            {
                return arr[midIndex];
            }
            else if (midIndex > 0 && arr[midIndex-1] == arr[midIndex])
            {
                return arr[midIndex];
            }
            else
            {
                l = midIndex+1;
            }   
        }
    }
    return -1; // not found
}
代码中用到的快速排序:
template <typename T>
void swap(T* lhs, T* rhs)
{
    T temp = *lhs;
    *lhs = *rhs;
    *rhs = temp;
}
template <typename T>
int partition(T arr[], int l, int r)
{
    int mid = l + (r-l)/2;
    int randIdx = std::rand()%(r-l+1)+l;
    swap(&arr[l], &arr[randIdx]);
    T v = arr[l];
    int j = l;
    for (int i = l+1; i <= r; i++)
    {
        if (arr[i] < v)
        {
            j++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[l], &arr[j]);
    return j;
}
template <typename T>
void __QuickSort(T arr[], int l, int r)
{
    if (l >= r)
    {
        return;
    }
    int q = partition(arr, l, r);
    __QuickSort(arr, l, q);
    __QuickSort(arr, q+1, r);
}
template <typename T>
void QuickSort(T arr[], int n)
{
    if (arr == nullptr || n < 0)
    {
        return;
    }
    __QuickSort(arr, 0, n-1);
}
One thought on “算法:寻找异常数字”
厉害啦