字典树+数组的前后部分数异或的最大值

一家日企的笔试题,实验室一个师兄投了一家日企的开发岗位,他们的笔试题是二选一,只要最后截止日期前向规定的邮箱发送代码即可,他们会通过验证代码的时间复杂度和空间复杂度来决定是否参加面试。其中一道就是:

      输入一个整型数组,假定数组中前x个数和后y个数的异或值为a,求出a的最大值,并且在最大值情况下的两个下标。

分析;

        因为要考虑时间复杂度和空间复杂度,因而肯定不能采用把每种情况都计算一遍,然后求得最大值,只能采用其他办法,字典树的思想可以应用。字典树的一个典型应用就是比较相同的前缀的单词,(例如在给定大量的单词中,有band ,banana,bee,ban,abc中,前缀为ba的有3个,ban的也有三个,b的有4个,这时我们假定都是小写单词,那么每个节点的子树有26个,依次为a到z,这样每一个单词都是一条从根节点到叶子节点的路径,这就是字典树,在建立完成后,当输入要查找的前缀时,便可以直接查找到,例如ba,可以先查找根节点的第二个子节点是否存在,若存在,则查找b的一个子节点是否存在,如果存在就输出该节点的value值,就是次数,代码一会也会贴出来,回到正题)在这里,字典树的层高是固定的就是32位,每一个节点都是0或者1(也可以理解为固定层高的二叉树),数组的假设为1、 2、3、4、5;1本身的二进制存到树里面,1、2的异或值也是一个32位的,存到树里面,1、2、3的异或值也存进去,以此类推,直到1、 2、3、4、5。然后从后面开始向前遍历,先是5,要想总的异或值最大,则要跟5的二进制表示中0的位置为1,1的位置为0,(5的二进制为00000000000000000000101,则使其异或值最大的值为1111111111111111111010)先在树中查找使5的异或值最大的值,然后再查找使4、5的异或值最大的值,以此类推,最后输出最大的异或值,并输出前后的下标。

#include 
#include 


using namespace std;
#define  MAX 2

typedef struct trie{   //字典树
	int v;//直到最后一个才存储位置,之前都存储为0
	int n;//存储异或值,但是只有叶子节点才存储这个值,其他节点这个值都设为0
	trie *next[MAX];

}trie;
trie *root = new trie();
void creatTrie(int *str,int location,int m) //建立字典树的过程,
{
	trie *p;
	trie *c_root=root;
	for(int i=0;i<32;i++)
	{
		int id=str[i];
		if (c_root->next[id]==NULL)
		{
			p=(trie *)malloc(sizeof(trie));
			if(i==31){
				p->n=m;
				p->v=location;
			}
			else{
				p->v=0;
				p->n=0;
			}
			for (int j=0;jnext[j]=NULL;
			}
			c_root->next[id]=p;
			c_root=c_root->next[id];

		} 
		else
		{
			c_root=c_root->next[id];
		}
		
	}

}

void Binarycout(int m[],int n)  //求32位的二进制,并存储在一个数组里
{  
	for (int i=31,j=0;i>=0,j<=31;i--,j++)  
	{  
		m[j]=((n>>i)&1);  
	}   
} 


trie  findTrielocation(int *str)  //
{
	trie *f_root=root;
	for(int i=0;i<32;i++)
	{
		int id=str[i];
		if (id==0){
			if (f_root->next[1]!=NULL)
			{
				f_root=f_root->next[1];
			}
			else{
				f_root=f_root->next[0];
			}
		}   		
		else{
			if (f_root->next[0]!=NULL)
			{
				f_root=f_root->next[0];
			}
			else{
				f_root=f_root->next[1];
			}
		}

	}
	return *f_root;

}

int main()
{

	for (int p=0;pnext[p]=NULL;
	}
	int num[50];
	int i=0,length;
	int m;
	while(cin>>m)
	{
		num[i++] = m;
	}
	length=i;
	int tmp=0;
	for (int k=0;k=0;--j)
	{
		temp=temp^num[j];
		int str2[32];
		Binarycout(str2,temp);
		tp=findTrielocation(str2);
		if (tp.n>max)
		{
			max=tp.n^temp;
			location_forward=tp.v;
			location_back=j;
		}
	}
	cout<
为了简单起见,最后运行结果是就是三个数,分别是前一个下标,后一个下标,最大的异或值

注意一点,因为没有限制数组的个数,因而在输入完成后先Ctrl+c,然后回车,这样就可以出结果,ctrl+c是判断结束的标识。


最后再附一个查找前缀的代码

#include 

//字典树的一个模板和典型应用
using namespace std;
#define  MAX 26

typedef struct trie{
	
	int v;
	trie *next[MAX];

}trie;
trie *root = new trie();
void creatTrie(char *str)
{
	trie *p;
	trie *c_root=root;
	int i=0;
	while(str[i]!='\0')
	{
		int id=str[i]-'a';
		if (c_root->next[id]==NULL)
		{
			p=(trie *)malloc(sizeof(trie));
			p->v=1;
			for (int j=0;jnext[j]=NULL;
			}
			c_root->next[id]=p;
			c_root=c_root->next[id];

		} 
		else
		{
			c_root->next[id]->v++;
			c_root=c_root->next[id];
		}
		i++;
		
	}

}

int  findTrie(char *str)
{
	int len=strlen(str);
	trie *f_root=root;
	for(int i=0;inext[id];
		if(f_root==NULL)
		{
			return 0;
		}		
	}
	return f_root->v;

}

int main()
{

	for (int i=0;inext[i]=NULL;
	}

	char str[20];
	while (gets(str)&&str[0]!='\0')
	{
            creatTrie(str);
	}
	char str1[20];
	while (gets(str1))
	{
	    cout<
这个需要你先出入单词,每个单词占一行,输完单词后,先回车一下,再输入要查找的前缀,回车后会直接输出结果


最后还是烦请多指正哟





你可能感兴趣的:(算法)