昨天下午打乒乓球了,爽爽的,各种抽球,以后多运动下,结果导致不想吃饭,吃个半个西瓜,结果肚子坏了,可悲,晚上看了两个算法,一个是关于重复数字的问题,统计出来,另一个是全排列。那就先说第一个吧,我也查了很多博客,各有各的想法,我整理了一下,1.给定数组A,大小为n,数组元素为1到n的数字,不过有的数字出现了多次,有的数字没有出现。请设计算法和程序,统计哪些数字没有出现,哪些数字出现了多少次。能够在O(n)的时间复杂度,O(1)的空间复杂度要求下完成么?

            关于详细的分析请参考 人家的解释的很清楚,这个里面设计到了面试常考的问题,你到底要牺牲哪一个,时间还是空间,很多算法习题,要不是时间换取空间,要不空间换取时间,一般很难做到二者兼得。下面我给出几种方法:

             

#include<iostream>

using namespace std;

int a[10000];

void repetitions(int a[], int n)
{
int i = 1;
for(i = 1; i <= n; ++i)
a[i] *= n;
for(i = 1; i <= n; ++i){
++a[a[i]/n];

}
for(i = 1; i <= n; ++i){
cout << i << "出现了" << a[i] % n << "次" << endl;
}
}
int main()
{
int n=10;
int i;
for(i=1;i<=n;i++)
scanf("%d",a+i);

repetitions(a,n);
for(i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}

 

上面的思路是:

首先,我们介绍一种三次遍历数组的方法,我们都考虑数组从0开始:
?第一次遍历:对于每一个a[i] = a[i] * n
?第二次遍历:对于每一个i,++a[a[i]/n]
?第三次遍历:对于每一个i,a[i] % n就是出现次数
a[i]应该出现在a中的a[i]位置,乘以n、再除以n,很容易的来回变换;第二次遍历,对于a[i]本来所在的位置不断增1,但绝对不对超出n的,那每一个i出现的次数,就是a[i]对n取余。

 

  这个人里面也有一种做法 

 

include<iostream>

using namespace std;

int a[10000];

void GetNums(int a[],int n)
{
if(a==NULL||n<=0)
{
return;
}
else
{
for(int i=0;i<n;i++)
{
//a[a[i]%n]+=n;//仔细研读处理技巧
a[a[i]%n]=a[a[i]%n]+n;
printf("%d ",a[a[i]%n]);

}
for(i=1;i<n;i++)
{
cout<<i<<":"<<(a[i]-1)/n<<endl;//思考为什么要减1(提示:数组中数据全部是N)
}
cout<<n<<":"<<(a[0]-1)/n<<endl;
}
}
int main()
{
int n=10;
int i;
for(i=0;i<n;i++)
scanf("%d",a+i);

GetNums(a,n);
for(i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}

上面的两句注释是他没有解释,我来解释一下,因为自己在那里确实遇到了问题,取余的话防止数组越界,对于一数如果已经出现了一次,那么对她加n,那么下次在a[a[i]]中不取余就会出问题了,还有那个为什么要-1,因为假如这个数没有出现,并且不-1,那么算出来的结果,就会记录她出现了一次。

 

第二道题是全排列的问题,这个真的很重要,面试题也经常出现,因为难度适中,而且也用到了递归。详细的解释看这个人的博客这个里面也涉及到了重复值的问题,考虑的很周到,值得一看。自己也差不多看懂。

#include <stdio.h>
#include <string.h>

void Swap(char *a,char *b)
{
char t;
t=*a;
*a=*b;
*b=t;
}
bool IsSwap(char *pszStr,int nBegin,int nEnd)
{
for(int i = nBegin;i<nEnd;i++)
if(pszStr[i]==pszStr[nEnd])
return false;
return true;
}
void AllRange(char *pszStr,int k,int m)
{
if(k==m)
{
static int s_i=1;
printf("第%3d个排列\t%s\n",s_i++,pszStr);
}
else
{
for(int i=k;i<=m;i++)
{
if(IsSwap(pszStr,k,i))
{
Swap(pszStr+k,pszStr+i);
AllRange(pszStr,k+1,m);
Swap(pszStr+k,pszStr+i);
}
}
}
}
void Foo(char *pszStr)
{
AllRange(pszStr,0,strlen(pszStr)-1);
}
int main(int argc, char const *argv[])
{
printf("去重全排列的递归实现\n");
char szTextStr[]="122";
printf("%s的全排列如下:\n",szTextStr);
Foo(szTextStr);
return 0;
}