您的位置:首页 > 理论基础 > 数据结构算法

定义一个栈的数据结构,实现min函数,要求push,pop,min时间复杂度是0(1);找出字符串中的最长子串,要求子串不含重复字符,时间复杂度是O(n);

2012-10-23 20:22 1131 查看
1.将IPV4转换成整数,要求高效。

2.定义一个栈的数据结构,实现min函数,要求push,pop,min时间复杂度是0(1);

3.数组a
里存有1到n的所有数,除了一个数removed,找出这个missing的数。
4.找出字符串中的最长子串,要求子串不含重复字符,时间复杂度是O(n);

第一题答案:

#include<stdio.h>

int change(char *a)
{
unsigned int n = 0,sum = 0,i = 2;
int m[] = {256,256*256,256*256*256};
while(*a != '\0')
{
if(*a != '.')
{
n = n*10 + *a - '0';
}
if(*a == '.')
{
sum = sum + n * m[i--];
n = 0;
}
a++;
}
sum = sum + n;
return sum;
}
int main(int argc,char *argv[])
{
char ip[] = "192.168.23.7";
unsigned int n;
n = change(ip);
printf("192.168.23.7->%u\n",n);

return 0;
}


第二题答案:

#include<stdio.h>
#define STACK_LEN 50

typedef struct
{
int data;
int min;
}stackitem;
typedef struct
{
stackitem data[STACK_LEN];
int top;
}stack;
void push(stack *s,int val)
{
s->data[s->top].data = val;
if(s->top > 0) 			// 保证栈顶元素中的min始终为当前栈中最小值
{
if(val < s->data[s->top-1].min)   // 如果当前push进的元素小于栈中最小元素值
s->data[s->top].min = val;	  // 把当前元素置为栈中最小元素值
else
s->data[s->top].min = s->data[s->top-1].min;
}
else		// 否则,不更新
s->data[s->top].min = val;
s->top++;
}
int pop(stack *s)
{
if(s->top-1 >= 0)
return s->data[--s->top].data;
else
return -1;
}
int min(stack*s)
{
if(s->top-1 >= 0)
return s->data[s->top-1].min;
else
return -1;
}
int main(int argc,char *argv[])
{
stack *s;
push(s,1);
push(s,2);
printf("%d\n",min(s));
printf("%d\n",pop(s));
return 0;
}


第四题其实很有难度,有好几种解法。

方法一:穷举法,使用2重外循环遍历所有的区间,用2重内循环检验子串是否符合“无重复字符”这一要求。其中外层循环i、j 遍历所有的下标,m、n是内层循环,检查区间[i,j]是否符合要求。空间复杂度是O(1),时间复杂度O(N^4)。

//O(N^4)的时间复杂度
#include<stdio.h>

int max_unique_substring1(char * str)
{
int maxlen = 0;
int begin = 0;
int n = strlen(str);
int i,j,m;
for(i=0; i<n; ++i)
for(j=1; j<n; ++j)
{
int flag = 0;
for(m=i; m<=j; ++m)
{
int n;
for(n=m+1; n<=j; ++n)
{
if(str
== str[m])
{
flag = 1;
break;
}
}
if(flag == 1) break;
}
if(flag==0 && j-i+1>maxlen)
{
maxlen = j-i+1;
begin = i;
}
}
printf("%.*s\n",maxlen,&str[begin]);
return maxlen;
}
int main(int argc,char *argv[])
{
char *str = "abcdafeeg";
printf("%d\n",max_unique_substring1(str));
return 0;
}


方法二:对方法一的检验子串是否“无重复字符”进行改进,使用hash表记录字符是否出现过。

//O(N^2)的时间复杂度
#include<stdio.h>

int max_unique_substring2(char * str)
{
int i,j;
int begin;
int maxlen = 0;
int hash[256];
int n = strlen(str);
for(i=0; i<n; ++i)
{
memset(hash,0,sizeof(hash));
hash[str[i]] = 1;
for(j=i+1; j<n; ++j)
{
if(hash[str[j]] == 0)
hash[str[j]] = 1;
else
break;
}
if(j-i > maxlen)
{
maxlen = j-i;
begin = i;
}
}
printf("%.*s\n", maxlen, &str[begin]);
return maxlen;
}
int main(int argc,char *argv[])
{
char *str = "abcdafeeg";
printf("%d\n",max_unique_substring2(str));
return 0;
}

方法三:对字符串“axbdebpqawuva”构造下表:



表中,字符串有3个‘a’,有2个‘b’,其余为单一字符。next[]记录了下一个与之重复的字符的位置,如str[0]=str[8]=str[12]=‘a’,这时next[0]=8,next[8]=12,next[12]=13,其余同理。值得注意的是,对于没有重复字符的,next[]存储字符结束符‘\0’的下标,即13。

这里,first[i]表示i之后,第一次出现重复字符的那个位置。例如,str[0]之后,第一次出现的重复字符是str[5]=‘b’,当然,从str[1],str[2]开始也是一样。而从str[3]开始,要到str[12]才出现重复字符‘a’。可以证明,从str[i]起的最长符合要求的长度为first[i]-i,区间为[i,first[i]-1]由此得解。上述最长串是当i=3时,first[i]-i=12-3=9。结果最长无重复子串为“debpqawuv”。

//O(N)的时间复杂度
#include<stdio.h>

int max_unique_substring3(char * str)
{
int maxlen = 0;
int begin = 0;
int n = strlen(str);
int * next = (int*)malloc(sizeof(int)*n); //next[i]记录了下一个与str[i]重复的字符的位置
int * first = (int*)malloc(sizeof(int)*(n+1)); //first[i]记录str[i]后面最近的一个重复点
int hash[256];
memset(hash,n,sizeof(hash));
first
= n;
int i;
for(i=n-1; i>=0; i--)
{
next[i] = hash[str[i]];
hash[str[i]] = i;
if (next[i] < first[i+1])
first[i] = next[i];
else
first[i] = first[i+1]; //生成first[]表,复杂度是O(N)的
}
for(i=0; i<n; i++)
{
if (first[i]-i > maxlen)
{
maxlen = first[i]-i;
begin = i;
}
}
free(first);
free(next);
printf("%.*s\n", maxlen, &str[begin]);
return maxlen;
}
int main(int argc,char *argv[])
{
char *str = "axbdebpqawuva";
printf("%d\n",max_unique_substring3(str));
return 0;
}


方法四:使用后缀数组

对这个字符串构造后缀数组,在每个后缀数组中,寻找没有重复字符的最长前缀,最长的前缀就是要找的子串。

#include<stdio.h>

//得到字符串最长的无重复的前缀长度
int longestlen(char * p)
{
int hash[256];
int len = 0;
memset(hash,0,sizeof(hash));
while(*p && !hash[*p])
{
hash[*p] = 1;
++len;
++p;
}
return len;
}
//使用后缀数组解法
int max_unique_substring4(char * str)
{
int maxlen = -1;
int begin = 0;
char *a[999];
int n = 0;
while(*str != '\0')
{
a[n++] = str++;
}
int i;
for (i=0; i<n; i++)
{
int temlen = longestlen(a[i]);
if (temlen > maxlen)
{
maxlen = temlen;
begin = i;
}
}
printf("%.*s\n", maxlen, a[begin]);
return maxlen;
}
int main(int argc,char *argv[])
{
char *str = "abcdafeeg";
printf("%d\n",max_unique_substring4(str));
return 0;
}


进一步精简:

#include<stdio.h>

//得到字符串最长的无重复的前缀长度
int longestlen(char * p)
{
int hash[256];
int len = 0;
memset(hash,0,sizeof(hash));
while(*p && !hash[*p])
{
hash[*p] = 1;
++len;
++p;
}
return len;
}
//使用后缀数组解法
int max_unique_substring4(char * str)
{
char *p=str;
int maxlen = -1;
int begin = 0;
int i;
for (i=0; i<strlen(p); i++)
{
int temlen = longestlen(str+i);
if (temlen > maxlen)
{
maxlen = temlen;
begin = i;
}
}
printf("%.*s\n", maxlen, p+begin);
return maxlen;
}
int main(int argc,char *argv[])
{
char *str = "abcdafeeg";
printf("%d\n",max_unique_substring4(str));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构
相关文章推荐