如何判定数组是否存在重复元素

题目:假设数组 array 有 n 个元素,元素取值范围是 1~n,如何判定数组是否存在重复元素?
方法一:对数组进行排序(可以用效率比较高的排序算法,如快速排序、堆排序等),然后比较相邻的元素是否相同。时间复杂度为 O(nlogn),空间复杂度为O(1)。下面借助c语言类库中自带的快速排序算法qsort,来实现排序。

#include 

int comp(const void *a, const void *b) // 注意const
{
    return *(int *)a - *(int *)b; // 升序
}

bool IsArrayRepeat(int *arr, int len)
{
    if (!arr || len <= 1)
        return false;


    qsort(arr, len, sizeof(int), comp);

    for (int i = 0; i < len - 1; i++)
    {
        if (arr[i] == arr[i + 1])
            return true;
    }

    return false;
}

int main(int argc, const char * argv[]) {

    int arr[7] = {1,2,3,4,5,6,2};
    int len = sizeof(arr)/sizeof(int);

    if (IsArrayRepeat(arr, len))
        printf("数组中存在重复元素\n");
    else
        printf("数组中不存在重复元素\n");

    return 0;
}

备注:上述程序的运行环境为:Xcode。
(1)qsort 是 C 标准库函数,包含在头文件 stdlib.h 中。
在 ISO C++中为 std::qsort,包含在文件 cstdlib 中。#include之后,可以直接调用 std::qsort 或 using namespace std;然后再调用 qsort。
(2)sort( )和qsort( )知识点补充: C++ 排序函数 sort(),qsort()的用法

方法二:Hash法 或者 位图法,时间复杂度 和 空间复杂度 都是 O(n)。

方法三:由于本题中数组array有 n 个元素,而且元素的取值范围是 1~ n,所以可以通过遍历数组,假设下标 i 位的数字为 j。那么通过交换,将“下标 i 位上的数字 j“ 交换到“下标 j - 1 位上“,直到所有数字都出现在自己对应的下标处,或发生了冲突。此算法的时间复杂度为O(n),空间复杂度为O(1)。

#include 

bool IsArrayRepeat2(int arr[], int len)
{
    if (!arr || len <= 1)
        return false;
    for (int i = 0; i < len; i++)
    {
        if (arr[i] <= 0 || arr[i] > len)
            return false;
    }

    int j = -1;
    for (int i = 0; i < len; i++)
    {
        j = arr[i];
        if (i == j - 1)
            continue;
        if (arr[i] == arr[j - 1])
            return true;
        arr[i] = arr[j - 1];
        arr[j - 1] = j;
        i--;
    }

    return false;
}

int main(int argc, const char * argv[]) {

    int arr[7] = {7,1,3,4,7,6,2};
    int len = sizeof(arr)/sizeof(int);

    if (IsArrayRepeat2(arr, len))
        printf("数组中存在重复元素\n");
    else
        printf("数组中不存在重复元素\n");

    return 0;
}

补充一个注意点,关于数组越界的问题(上述代码的运行环境,均为Xcode):

bool IsArrayRepeat2(int arr[], int len) // 主要针对IsArrayRepeat2做一些说明
{
    if (!arr || len <= 1)
        return false;

     // 如果把IsArrayRepeat2中的这段代码注释掉,那么当原arr[7]数组中出现0、-1、8等数字时,虽然会造成arr[j-1]越界,但是程序仍然能正常运行,没有报错。但是输出是错误的,数组越界时访问到的数值会给输出带来异常,所以加上这段代码很有必要。
//    for (int i = 0; i < len; i++)
//    {
//        if (arr[i] <= 0 || arr[i] > len)
//            return false;
//    }

    int j = -1;
    for (int i = 0; i < len; i++)
    {
        j = arr[i];
        if (i == j - 1)
            continue;
        if (arr[i] == arr[j - 1])
            return true;
        arr[i] = arr[j - 1];
        arr[j - 1] = j;
        i--;
    }

    return false;
}

你可能感兴趣的:(算法)