阿里巴巴2015年秋季在线笔试附加题---求交集字符串

7 篇文章 2 订阅
6 篇文章 0 订阅

给定一个query和一个text,均由小写字母组成。要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度。例如, query为“acbac”,text为“acaccbabb”,那么text中的“cba”为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3。请注意程序效率。


想了好多种方法,姑且先说几种有创意的..

第一种,打卡遮盖型

画得有点丑,有点不规范不要在意,能理解就最好.

明显这是一种空间换时间的算法.

时间复杂度就是O(n+m)

空间复杂度O(n*m)



第二种,过火车匹配


从头过到尾

其实这种就是最普通的一种

时间复杂度O(n*m)

空间复杂度O(1)


第三种,求出next[ ]改进.

正如KMP算法那样,有很多比较是多余可跳过的.

比如说上面的,比较第一个字符a,而后失配时可以直接跳到第4个字符a,再跳到第10个字符a

中间的就可以忽略了,反正都肯定是不匹配的.

不过建立next[ ]也需要一定的时间(O(n²)),对于很长的字符串他的作用才能明显发挥.

void  GetNextVal(char *str)
{
  int  next [ 30 ]= { 0 };
  int len=strlen(str);
  for( int i = 0 ; i< len ; i++)
   {
   if( next [ i ]  == 0 )
    {
      int j=i+1;
      while (str [ i ] != str [ j ]  &&  j < len  ||  next [ j ]  != 0 )  j++;
          if( j != len)   next[ i ]  = j;
              else  next[ i ] = -1;     
     }
  }
}


第四种,用哈希函数建立索引

这种又是上一种的改进.用哈希建立索引只需要O(n)即可.

比如说: 

文本串: 157369824704

对于每个字符进行分类,设哈希函数 f(n)=n mod 10 = d;

那么

f(A[0])=[1] mod 10 =1 ;

f(A[1])=[5] mod 10 =5 ;

f(A[2])=[7] mod 10 =7;

f(A[3])=[3] mod 10 =3 ;

f(A[4])=[6] mod 10 =6;.....


这样可以得到一个索引

索引0:  10->null;

索引1:  0->null;

索引2:  7->null;

索引3:  3->null;

索引4:  8 ->11->null;

索引5:  1->null;

索引6:  4->null;

索引7:  2->9->null;

................


然后假设模式串是59826

对  第一个字符使用哈希函数

得到 对应位置是  先比较位置1,得到最长匹配为1

对第二个使用哈希,得到比较位置5,比较成功得到最长匹配为3

对第三个使用哈希.得到比较位置6,得到最长匹配为2

...............


可见这种拥有是时间复杂度O(n)~O(n*m)是效率不错的.

至于空间复杂度,看哈希函数怎么设定了.



以下是我写的代码,对以上几种想法都采取一点而改进成.

主体还是以一定的空间换时间,而后匹配方面采用Sunday算法加速.

用链表的形式来做索引,用数组来表达得到的key值

这样组合起来就得到一个...(后来查了下) 散列表,也叫hash表.   (我想了大半个下午原来已经早被发明也还是教科书的东西∑(゚Д゚)

先是散列表的数据结构 代码

#include <stdio.h>
#include <stdlib.h>  //malloc需要用
#include <string.h>
#define Len 11

/******************************
         哈希表头
 ******************************/
typedef struct HashHeader    
{    
    struct Node *next;    
}HashHeader,*PHashHeader; //写了typedef这两个是结构体,不写则是变量

PHashHeader HashTable[Len];

//初始化表头
PHashHeader InitHashTable(void)
{
	PHashHeader node;
	node=(PHashHeader)malloc (sizeof(PHashHeader));
	node->next=NULL;
	return node;
}

//初始化哈希表
void InitTable()
{
	for(int i=0;i<Len;i++)
	HashTable[i]=InitHashTable();
}
/*******************************
          节点
******************************/
typedef struct Node
{
	int data;
	Node *next;
}Node,*PNode;   

 PNode PEnd[Len];

//哈希函数
int HashFunc(char c)
{
   int	key=(int)c % Len;
   return key;
}

//加节点
void AddNode(char c,int i)
{
	PNode node;
	int key=HashFunc(c);
	node=(PNode)malloc (sizeof(PNode));
	node->data=i;
	node->next=NULL;
	if(HashTable[key]->next==NULL) 
	{
		HashTable[key]->next=node;
		PEnd[key]=node;
	}
	else if(PEnd[key]->next==NULL)
	{
	PEnd[key]->next=node;
	PEnd[key]=node;
	}
	else printf("error");
}

void PrintHash()
{
	PNode Pr;
	for(int i=0;i<Len;i++)
		if(HashTable[i]->next!=NULL )
		{
			Pr=HashTable[i]->next;
			while(Pr !=NULL)
			{
				printf("%4d",Pr->data);
                Pr=Pr->next;
			}
			printf("\n");
		}
}

int main()
{
	char Tstr[30];
	printf("输入文本串:");
	gets(Tstr);
	int Tlen=strlen(Tstr);
	InitTable();
	for(int i=0;i<Tlen;i++)
		AddNode(Tstr[i],i);

        PrintHash();
	return 0;
}

运行结果:



以下则是题目要求的函数

int jiaoji(char *Tstr,char *Mstr)
{
	int max=0;
	int Tlen=strlen(Tstr);
	int Mlen=strlen(Mstr);
	InitTable();

	int i,j;
	for(i=0;i<Tlen;i++)
	   AddNode(Tstr[i],i);

	for(i=0;i<Mlen;i++)
	{
	 j=HashFunc(Mstr[i]);
     if(HashTable[j]->next !=NULL )
	 {
		 PNode Pr=HashTable[j]->next;
		 while(Pr != NULL)
		 {
		 int data=Pr->data;
		 int k=max-1;       //类似Sunday算法,从尾部开始比较,反正目的只是取最大
		 while(Tstr[data+k] == Mstr[i+k] && data+k < Tlen && i+k< Mlen)k++;
		 max=max<k?k:max;
		 Pr=Pr->next;
		 }
     }
	}

	return max;
}

int main()
{
	char Tstr[30],Mstr[20];
	printf("输入较长的串:");
	gets(Tstr);
	printf("输入较短的串:");
	gets(Mstr);
    
	int max=jiaoji(Tstr,Mstr);
     printf("最多相交部分长度是%d",max);
	return 0;
}

上文用到的是较长 和 较短 的字符串, 因为 长的用来做哈希比较好, 这样用短的每个寻址就可以了.

空间复杂度..O(n+m)

时间复杂度  O(n+m)

效率还可以吧..测了几个例子都

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在模拟芯片设计笔试中,选择通常是考察对于模拟电路和芯片设计相关知识的理解和应用能力。目的难度和类型可能会有所不同,下面我将简单回答此类目的一般性特点。 首先,模拟芯片设计选择往往会涉及到模拟电路的基本概念和理论知识,如放大器、滤波器、振荡器等。我们需要了解各种电路的工作原理、频率响应和稳定性等特性,以及其在芯片设计中的应用。此外,对于模拟电路中的元器件,如电容、电感、二极管和晶体管等,也需要熟悉其特性和工作原理。 其次,模拟芯片设计选择还可能考察电路的分析和计算能力。例如,给定一个电路图形,要计算某些电路参数或分析电路的性能。这需要掌握基本的电路分析方法和技巧,如基尔霍夫定律、戴维南-诺顿等效电路等。同时,还需要具备一定的数学基础,能够进行复数运算和解微分方程等。 此外,在模拟芯片设计选择中,可能会提到一些常用的设计工具和软件,如SPICE软件、面向对象设计和硬件描述语言等。我们需要了解这些工具和软件的原理和使用方法,以及它们在芯片设计中的应用。 总体而言,在模拟芯片设计选择中,强调对于模拟电路基本概念和理论的理解与应用,同时要一定的计算和分析能力。为了更好地完成模拟芯片设计笔试目,我们需要扎实的电路基础和数学基础,并且经常进行习练习和实际项目实践,提高我们的设计和分析能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值