惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Y
Y Combinator Blog
D
DataBreaches.Net
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
I
InfoQ
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
A
About on SuperTechFans
人人都是产品经理
人人都是产品经理
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
C
Cybersecurity and Infrastructure Security Agency CISA
Know Your Adversary
Know Your Adversary
MongoDB | Blog
MongoDB | Blog
T
Tor Project blog
The Register - Security
The Register - Security
H
Help Net Security
Cisco Talos Blog
Cisco Talos Blog
P
Privacy & Cybersecurity Law Blog
NISL@THU
NISL@THU
P
Palo Alto Networks Blog
B
Blog RSS Feed
Latest news
Latest news
T
Threat Research - Cisco Blogs
The Hacker News
The Hacker News
C
Cisco Blogs
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
S
Schneier on Security
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
Google Online Security Blog
Google Online Security Blog
H
Hacker News: Front Page
N
News and Events Feed by Topic
W
WeLiveSecurity

博客园 - Be Myself

安装Docker Toolbox后出现的问题 SharePoint 2013 必备组件之 Windows Server AppFabric 安装错误 Exchange WebSerivce Usage 日志记录组件 ASP.NET 中执行 URL 重写 Could not load file or assembly 'System.Data.SQLite' or one of its dependencies Visual Studio 2012 cannot identify IHttpActionResult distributed caching for .net applications HTTP Error 503. The service is unavailable windows 7 HTTP Error 500.21 - Internal Server Error resolution ! C#字符串反转 - Be Myself - 博客园 HTTP could not register URL http://+:****/WCFService/. Your process does not have access rights to this namespace CSpider 安装和配置branchcache asp.net下url参数含有中文读取后为乱码 时间复杂度为O(n)的排序算法 IIS 7.0 HTTP 错误 404.3 - Not Found解决办法 博文阅读密码验证 - 博客园 MSMQ, WCF and IIS: Getting them to play nice (Part 3)[转]
找出数组中是否有重复的数
Be Myself · 2008-12-23 · via 博客园 - Be Myself

题目是这样的, 数组是无序的, 可能没有重复的数,但最多只可能有一个重复的数,要求用最快的方法找到是否有重复的数。

乍一想,挺难的,但是其实非常的简单。

解决办法:

数组a[N]1N-1N-1个数存放在a[N]中,其中某个数重复一次。写一个函数,找出被重复的数字。时间复杂度必须为oN函数原型:

int do_dup(int a[],int N)

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

假金条的数学思想

此算法题借鉴了假金条的思想,不过比那个过程简单,存放1N-1,就相当于依次从各个袋中取出1N-1个金条,但是有一个是重的,计算这N个数的和将相当于称总重量,减去1N-1的和(用数学方法求)就可求出来重复的数。总之要充分利用数学知识

const int N = 5;

int a[N]={2,1,3,1,4};

int tmp1 = 0;

int tmp2 = 0;

for (int i=0; i<N; ++i)

{

tmp1+=(i+1);

tmp2+=a[i];

}

printf("重复的数:%d\n",N-(tmp1-tmp2));

上述方法求1~N的和,减去数组总和,即为N-x 的差值,x为待找的数

可以优化的是1-N的和不用程序算,数学方法直接算了

可定义一个宏,

#define sum(x)  (x(x+1)/2)

当然乘法操作是比较复杂的,当N较小时加几个数的效率可能更高

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

标志数组法

申请一个长度为n-1且均为'0'组成的字符串。然后从头遍历a[n]数组,取每个数组元素a[i]的值,将其对应的字符串中的相应位置置1,如果已经置过1的话,那么该数就是重复的数。就是用位图来实现的。

其实,只要数还是0 -- n-1里面的数,那么可以用这样的方法判断所有的重复数的位置和值。

比如这样的一个数组

{2,3,1,2}

我们生成一个字符串"000";

然后开始遍历,a[0] = 2;

所以,字符串的第二位为"0",那么我们将其置为"1"

字符串为"010"

重复,字符串为"011",,,,,"111"

然后,判断a[3] = 2 那么 第二位为"1"

所以,a[3]为重复数,并且位置为第4位。

上述map等各方法的思路是一致的,即访问过后做标记,再次访问时即可知道是否重复。如果考虑空间复杂度的话,其空间oN

int do_dup(int arr[],int NUM)

{

        int *arrayflag = malloc(NUM*sizeof(int));

        while(i++<NUM)

        arrayflag[i] = false;

        for(int i=0; i<NUM; i++)

        {

                if(arrayflag[arr[i]] >= false)

                       arrayflag[arr[i]] >= true;           // 置出现标志

                else

                       return  arr[i]; //返回已经出现的值

        }

}

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

固定偏移标志法

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

不改变A[]的初始值

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

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

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

a[N],里面是1N-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符号位闲着也是闲着)

bool 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;//没有重复

}

//用于修复数组

void restorearray(int array[],int n)

{

        for(int i=0;i<n;i++)

        {

        if(array[i]<0)array[i]= array[i];

        }

}

时间复杂度on 空间复杂度o1

不过时间复杂度on 空间复杂度o1)不只一个重复利用此法也是可以实现的

//附上我修改后的算法
bool do_dup_mal(int arr[], int n, int *pre, int *back)
{
int MAX = -1;
int i = 0;
int sameVal = -1;
assert(pre && back);
*pre = *back = -1;

for (int j=0; j<n; j++)
{
if (arr[j] > MAX) MAX = arr[j];
}

char *arrayflag = new char[MAX+1] ;
if (NULL == arrayflag)
return -1;
//while(i++ < MAX) arrayflag[i] = '\0';
memset(arrayflag, 0, MAX+1 ); // '\0' == 0
for(i=0; i<n; i++)
{
if(arrayflag[arr[i]] == '\0')
arrayflag[arr[i]] = '\1'; // 置出现标志
else
{
sameVal = arr[i]; //返回已经出现的值
*back = i;
break;
}
}
delete[] arrayflag;
if (i < n)
{
for (int j=0; j<n; j++)
{
if (sameVal == arr[j])
{
*pre = j;
return true;
}
}
}
return false;
}

int main(int argc, char *argv[])
{
int prePos = -1, backPos = -1;
int myArry[N];
myArry[0] = 1;
myArry[1] = 23;
myArry[2] = 3;
myArry[3] = 4;
myArry[4] = 5;
myArry[5] = 22;
myArry[6] = 7;
myArry[7] = 8;
myArry[8] = 9;
myArry[9] = 22;
myArry[10] = 12;

if (do_dup_mal(myArry, 11, &prePos, &backPos) )
printf("\nT