判断数组中是否包含重复数字

给定一个长度为N的数组,其中每个元素的取值范围都是1到N。判断数组中是否有重复的数字。(原数组不必保留)

 

方法1.
对数组进行排序(快速,堆),然后比较相邻的元素是否相同。
时间复杂度为O(nlogn),空间复杂度为O(1)。

方法2.
使用bitmap方法。
定义长度为N/8的char数组,每个bit表示对应数字是否出现过。遍历数组,使用 bitmap对数字是否出现进行统计。
时间复杂度为O(n),空间复杂度为O(n)。

方法3.
遍历数组,假设第 i 个位置的数字为 j ,则通过交换将 j 换到下标为 j 的位置上。直到所有数字都出现在自己对应的下标处,或发生了冲突。
时间复杂度为O(n),空间复杂度为O(1)。

方法3示例代码如下:

bool isUnique(int *X, int N)
{
    for(int i=0; i<N; ++i)
    {
        if(X[i] != i+1)//X[i]不在自己的位置
        {
            if(X[X[i]-1] == X[i])return false;
            swap(X[i], X[X[i]-1]);
        }
    }
    return true;
}

方法4.

××××××××××××××××××××××××××××××××××

固定偏移标志法

 

利用标记法单纯写个O(N)的方法并不难,关键是如何保证两点:

不改变A[]的初始值

函数内不开辟另外的O(N)内存空间.

 

很明显上述方法申请了O(N)内存空间,当N过大时,性能降低了

因此应利用a[N]本身中值和下标的关系来做标记,处理完成后再清除标记即可

 

a[N],里面是1至N-1。原数组a[i]最大是N-1,若a[i]=K在某处出现后,将a[K]加一次N,做标记,当某处a[i]=K再次成立时,查看a[K]即可知道K已经出现过。a[i]在程序中最大也只是N-1+N=2N-1溢出了怎么办啊???),此为一个限制条件

 
int do_dup(int arr[],int NUM)
{
    int temp=0;
 
    for(int i=0; i<NUM; i++)
    {
        if(arr[i]>=NUM)
           temp=arr[i]-NUM;            // 该值重复了,因为曾经加过一次了
        else 
           temp=arr[i];
 
        if(arr[temp]<NUM)
        {
            arr[temp]+=NUM; //做上标记
        }
        else
        { 
            printf("有重复");    
            return temp;
        }
    }
 
    printf("无重复");
    return -1;
}


上面就是时间复杂度O(N), 空间复杂度O(1)的算法!

 

××××××××××××××××××××××××××××××××××

符号标志法

 

上述方法将元素加一个固定的NUM来做标记,可能会造成溢出。下列方法中利用符号位来做标记,因为1~N都为正值,所以就无限制了。基本思想是用int数组的符号位作哈希表。(反正不是unsigned int符号位闲着也是闲着)

int dup(int array[],int n)
{
     for(int i=0;i<n;i++)
     {
         if(array[i]>0) //可以以此作下标去判断其他值
         {
              if(array[array[i]]<0)
              {
                    return array[i];//已经被标上负值了,有重复
              }
              else 
              {
                    array[array[i]]= -array[array[i]]; //否则标记为负
              }
         }
         else // |array[i]|代表的值已经出现过一次了
         {
              if(array[-array[i]]<0)
              {
                    return -array[i];//有重复
              }
              else 
              {
                    array[-array[i]]=-array[-array[i]];
              }
         }
     }
     return -1;//没有重复
}


收集整理自以下两篇博客:

http://hi.baidu.com/nicker2010/item/9cbed11c6811b8707a5f2513

http://www.cnblogs.com/relang99/archive/2008/12/23/1360773.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值