定義一個棧的數據結構,實現min函數,要求push,pop,min時間複雜度是0(1);找出字符串中的最長子串,要求子串不含重複字符,時間複雜度是O(n);

1.將IPV4轉換成整數,要求高效。
2.定義一個棧的數據結構,實現min函數,要求push,pop,min時間複雜度是0(1);
3.數組a[n]裏存有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;
}



第二題答案:spa

#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;
}



第四題其實頗有難度,有好幾種解法。
.net

方法一:窮舉法,使用2重外循環遍歷全部的區間,用2重內循環檢驗子串是否符合「無重複字符」這一要求。其中外層循環i、j 遍歷全部的下標,m、n是內層循環,檢查區間[i,j]是否符合要求。空間複雜度是O(1),時間複雜度O(N^4)。code

//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[n] == 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表記錄字符是否出現過。ip

//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」構造下表:rem

表中,字符串有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] = 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;
}



方法四:使用後綴數組get

對這個字符串構造後綴數組,在每一個後綴數組中,尋找沒有重複字符的最長前綴,最長的前綴就是要找的子串。

#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;
}
相關文章
相關標籤/搜索