子串子序列相关面试题总结

来源:互联网 发布:数据库的简单实现 编辑:程序博客网 时间:2024/05/16 14:55
注:子串是连续的,子序列则不连续

1,求最长回文子串

中心法应该是最为普通的办法,时间复杂度O(n^2)。当然用后缀树或者后缀数组也可以降低时间复杂度,不过这个我不熟就不写了。输入字符串假设为”abcdedc";从左到右依次考虑以a为中心最长回文是多少,以ab中间的空为中心最长回文是多少,以b为中心最长回文是多少.......

代码如下:

int LPS(char *str, int n){assert(str != NULL);int len = 0;int i, temp;int l,r;for (i=0; i<n; i++){l = i-1;r = i+1;temp = 1;while (l>=0 && r<n && str[l]==str[r]){l--;r++;temp = temp + 2;}if (temp > len)len = temp;l=i;r=i+1;temp = 0;while (l>=0 && r<n && str[l]==str[r]){l--;r++;temp = temp + 2;}if (temp > len)len = temp;}return len;}

2,求最长回文子序列

 这道题可以用递归来解决。对于一个输入的数组,首尾下标分别为begin,end,函数原型为int LPS(int a[], int begin, int end);我们可以分为下列几种情况来讨论:

      1,begin>end;直接返回0;
      2,begin == end;只有一个元素,天然就是回文,返回1;
      3,begin<end时分两种情况讨论
           1) a[begin] == a[mid];应该返回 LPS(a, begin+1, end-1) + 2;两边向中间收拢。
           2) a[begin] != a[mid];这时有两种情况,应该返回较大值,即max(LPS(a,begin+1,end), LPS(a,begin,end-1))

根据上述思路形成递归代码:

int LPS(char *s, int begin, int end){assert(s != NULL);if (begin > end)return 0;if (begin == end)return 1;else{if (s[begin] == s[end])return LPS(s, begin+1, end-1) + 2;else{return max(LPS(s,begin+1,end), LPS(s,begin,end-1));}}}

3,求最长公共子串

int LCS2( char *str1, char *str2){int len1 = strlen(str1);int len2 = strlen(str2);int *cl = new int[len2+1];int max = 0;int i, j;int start, end;for (i=0; i<=len2; i++){cl[i]=0;}for (i=0; i<len1; i++){for (j=len2-1; j>=0; j--){if (str1[i] == str2[j]){cl[j+1] = cl[j] + 1;if (cl[j+1] > max){max = cl[j+1];end = j;}}else{cl[j+1] = 0;}}}start = end - max + 1;for (i=start; i<=end; i++){cout << str2[i] << " " ;}return max;}

4,求最长公共子序列

int LCS(char str1[], int astart, int aend, char str2[], int bstart, int bend){if (astart > aend || bstart > bend)return 0;if (str1[astart] == str2[bstart]){return LCS(str1,astart+1,aend,str2,bstart+1,bend) + 1;}else{return max(LCS(str1,astart+1,aend,str2,bstart,bend), LCS(str1,astart,aend,str2,bstart+1,bend));}}

5,求最长连续递增子串

比如输入”abcd12345ed125ss123456789“,最长的为”123456789“,所以返回9。这个题比较简单,顺序遍历即可,时间复杂度O(n)。

代码:

int LIS(char *str){assert (str != NULL);int len = strlen(str);int cur = 1, max = 0;int start, end, temp = 0;for (int i = 1; i < len; i++){if (str[i] == str[i-1] + 1){cur++;}else   //不满足连续递增了,立即更新一些状态{if (cur > max){max = cur;start = temp;end = i-1;}temp = i;cur = 1;}if (i == len-1)       //这里是特殊处理,针对处于整个字符串末尾的最长字符串{if (cur > max){max = cur;start = temp;end = i;}}}for (i = start; i <= end; i++)cout << str[i];cout << endl;return max;}

6,求最长递增子序列

输入一个字符串str { "a d e f e g“},其最长递增子序列为 "a d f g“ 或者 ”a e f g “ 。该如何实现这个算法呢?我们定义一个数组lis[N]表示以下标 结尾的元素的最长递增子序列长度。lis[i]初始时为1,此时只有本身一个元素,但是下标i之前的元素可能大于str[i];所以要遍历从0到i-1的元素,检查是否有元素str[j]值大于str[i],若有且满足lis[j]+1>lis[i],lis[i]=lis[j]+1;最后扫描lis[N]求出最大值即可。这种方法整个时间复杂度O(n^2)。

代码:

int LIS(char *str){assert(str != NULL);int len = strlen(str);int i, j, max = 0;int *lis = new int[len];for (i=0; i<len; i++){lis[i] = 1;for (j=0; j<i; j++){if (str[j] < str[i] && lis[j] + 1 > lis[i]){lis[i] = lis[j] + 1;}}}for (i=0; i<len; i++){if (lis[i] > max)max = lis[i];}return max;}

这个问题还可以优化到O(nlgn),以后补充。

7,求最大子串和

这是最经典最常见的一道题,这里直接给出代码,代码中加了两个变量来标记最大子串的起始位置。

int SubMaxSum(int a[], int n) //子数组最大和{int sum=0;int max=0;int begin, end;int temp = 0;for (int i=0; i<n; i++){if (sum + a[i] < 0){sum = 0;temp = i+1;}else{sum += a[i];if (sum > max){max = sum;begin = temp;end = i;}}}for (i=begin; i<=end; i++)cout << a[i] << " ";cout << endl;return max;}
8,求最大子串积
见这篇博文:http://blog.csdn.net/cl512976287/article/details/21337185
0 0
原创粉丝点击