一个、升序矩阵问题
问题叙述性说明:例如,看到下面的数字,在一个m*n矩阵中,每一行都依照从左到右递增的顺序排序。每一列都依照从上到下递增的顺序排序。请完毕一个函数,按从小到大的顺序打印这个矩阵到一个一维数组中。
如图。则应打印出1,2,2,4,4,6,7,8,8,9,9,10,11,12,13,15.
二、无反复的最长子串问题(引用luxiaoxun博客)
问题描写叙述:找到一个字符串中的一个连续子串,这个子串内不能有不论什么两个字符是同样的。而且这个子串是符合要求的最长的。比如输入"abcbef",输出"cbef"。
问题求解:方法一:穷举法,使用2重外循环遍历全部的区间,用2重内循环检验子串是否符合“无反复字符”这一要求。
当中外层循环i、j 遍历全部的下标,m、n是内层循环,检查区间[i,j]是否符合要求。
空间复杂度是O(1),时间复杂度O(N^4)。
//O(N^4)的时间复杂度 int max_unique_substring1(char * str) { int maxlen = 0; int begin = 0; int n = strlen(str); for(int i=0; i<n; ++i) for(int j=1; j<n; ++j) { int flag = 0; for(int m=i; m<=j; ++m) { for(int 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 ", maxlen, &str[begin]); return maxlen; }方法二:对方法一的检验子串是否“无反复字符”进行改进,使用hash表记录字符是否出现过。
//O(N^2)的时间复杂度 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 ", maxlen, &str[begin]); return maxlen; }方法三:对于字符串"axbdebpqawuva",构造下表:
表中。字符串有3个‘a’。有2个‘b’,其余为单一字符。next[]记录了下一个与之反复的字符的位置,如str[0]=str[8]=str[12]=‘a’,这时next[0]=8。next[8]=12,next[12]=13,其余同理。
值得注意的是。对于没有反复字符的。next[]存储字符结束符‘ ’的下标,即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)的时间复杂度 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; for(int 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(int i=0; i<n; i++) { if (first[i]-i > maxlen) { maxlen = first[i]-i; begin = i; } } free(first); free(next); printf("%.*s ", maxlen, &str[begin]); return maxlen; }方法四:使用后缀数组
对这个字符串构造后缀数组。在每一个后缀数组中,寻找没有反复字符的最长前缀,最长的前缀就是要找的子串
//得到字符串最长的无反复的前缀长度 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[99999]; int n = 0; while(*str != '