剑指offer 面试题3:数组中重复的数字


题目描述:找出数组中重复的数字

    在一个长度为n的数组中,所有数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道几个数字重复了,也不知道数字重复了几次。请找出数组中所有的重复的数字。例如:一个长度为7的数组{2,3,1,0,2,5,3},数组中重复的数字是2和3。


解法一:排序法。把数组中的数字进行排序,在排序后的数组中扫描。在众多排序算法中,选择快速排序可以比简单选择排序和冒泡排序的时间复杂度低,而且编码也比较简单。采用这种方法的时间复杂度为:O(nlog(n))。

示例代码:

#include <iostream>

using namespace std;

void quicksort(int *a,int left,int right)
{
     int i = left, j=right, t;
     if (left > right)
     {
        return;
     }
     int tmp = a[left];
     while(i != j) 
     {
         while (a[j] >= tmp && j > i)
         {
               j--;
         }
         if(j > i)
         {
              a[i] = a[j];//a[i]已经赋值给tmp,a[j]赋值给a[i]之后 ,a[j]留出空位 
         }
         
         while(a[i] <= tmp && i < j) 
         {
               i++;
         }
         if(i < j)
         {
              a[j] = a[i];//此时a[i] 空出来了 
         }
     }
     a[i] = tmp;
     quicksort(a,left,i-1);
     quicksort(a,j+1,right);
}

int main()
{
    int a[] = {2,3,1,0,2,2,2,5,3};
    quicksort(a,0,8);
    for(int i = 0;i < 9; i++)
    {
            printf("%d ",a[i]);
    }
    printf("\n");
    int flag = 0;
    for(int i = 1;i < 9; i++)
    {
            if(a[i] == a[i+1])
            {
                    flag = 1;
            }
            else if(flag == 1)
            {
                 printf("%d ",a[i]);
                 flag = 0;
            }
    }
    printf("\n");
    getchar();
    return 0;
}

解法二:哈希法。扫描数组中的每个元素,同时把每个元素作为键,元素在数组中出现的次数作为值存储在哈希表中,经过一轮扫描之后,在哈希表中记录了数组中每个元素出现的次数。然后遍历哈希表,即可找出数组中重复的元素。采用这种方法的时间复杂度为O(n),空间复杂度为O(n)。因此,可以认为解法二提高时间复杂度是以牺牲了空间为代价的。

示例代码:

#include <iostream>
#include <map>

using namespace std;

int main()
{
    int a[] = {2,3,1,0,2,5,3};
    map<int,int> my_map;
    for(int i = 0;i < 7; i++)
    {
            if(my_map.find(a[i]) == my_map.end())
            {
                 my_map[a[i]] = 1;
            }
            else 
            {
                 my_map[a[i]]++;
            }
    }
    
    for(map<int,int>::iterator iter = my_map.begin();iter != my_map.end();iter++)
    {
        if(iter->second > 1)
        {
            printf("%d ",iter->first);
        }
    }
    printf("\n");
    getchar();
    return 0;
}

解法三:交换法。题中给出的是一个长度为n的数组,数组的下标是0~n-1,数组中的数字也是0~n-1。因此,当数组中不存在重复数字且排序之后,数字i将出现在下标为i的位置。由于数组中存在重复数字,因此,按照上面的思路,存在有的位置没有数字,有的位置要存放多个相同的数字。

    根据这种思路,我们可以采用交换法解决这个问题。扫描数组,每扫描一个数字,就比较当前数字是否与其下标相等,若相等,继续向后扫描;若不相等,比较以该数字为下标的元素是否与该元素相等,若相等,说明该元素是一个重复元素,向后扫描,否则,交换该元素和数组中以该元素为下标的元素。

示例代码:

#include <iostream>

using namespace std;

int main()
{
    int a[] = {2,3,1,0,2,5,3,2,3};
    int t;
    for(int i=0;i<9;) 
    {
       if(a[i] != i)     
       {
            if(a[a[i]] == a[i]) 
            {
                printf("%d ",a[i]);
                i++;
            } 
            else
            {
                t = a[i];
                a[i] = a[a[i]];
                a[a[i]] = t;
            } 
       }
       else
       {
       		i++;
	   }
    }
    return 0; 
}

有新想法或者问题欢迎留言。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值