面试小结
TX
1. 链表反转
2. 最大公共子串(两种方法,动态规划那种)
3. 进程与线程区别
4. 为何转后台
5. 栈空间的最大值是多少
最大公共子串:
int LCS(char s1[], char s2[])
{
int len1 = strlen(s1);
int len2 = strlen(s2);
int **c = new int *[len1 + 1];
for (int i = 0; i < len1 + 1; i++)
c[i] = new int[len2 + 1];
for (int i = 0; i < len1 + 1; i++)
c[i][0] = 0;
for (int j = 0; j < len1 + 1; j++)
c[0][j] = 0;
int max = -1, x = 0, y = 0;//max分别表示最大的公共子串长度。x与y分别表示下标
for (int i = 1; i < len1 + 1; i++)
for (int j = 1; j < len2 + 1; j++)
{
if (s1[i - 1] == s2[j - 1])
c[i][j] = c[i - 1][j - 1] + 1;
else
c[i][j] = 0;
if (c[i][j]>max)
{
max = c[i][j];
x = i;
y = j;
}
}
if (max > 0)
{
int i = x - 1, j = y - 1, k = max;
char *s = new char[k];
s[k] = '\0';
k--;
while (k >= 0)
{
s[k--] = s1[i];
i--;
}
cout << "最大公共子串是: " << s << endl;
}
return max;
}
讲解:
用c[i][j]来表示 以s1的第i个字母为结束的子串和以s2的第j个字母结束的子串所拥有的最大子串长度。
注意:必须包含s1[i]和s2[j]。
则如果s1[i]==s2[j]
c[i][j]=c[i-1][j-1]+1
否则
c[i][j]=0。
求解时,先声明一个变量来存储结果:c[len1+1][en2+1];
为何要声明为(len1+1)*(len2+1)这个长度,是因为我们要初始化两个边界:c[0][0~len1]和c[0~len2][0]。它们开始都是0,所以需要多1个长度。
然后根据递推公式计算可得。
最长公共子序列
c[i][j]表示字符串s1的前i个和字符串s2的前j个所能有的最长公共子序列。注意这里的实际含义和前面的最长公共连续子串是不一样的!!!
递推公式:
if(s1[i]==s2[j])
c[i][j]=c[i-1][j-1]+1;
else
c[i][j]=max(c[i-1][j],c[i][j-1]);
注意打印时调用PrintlongestSubSequence,递归打印!!!
void PrintlongestSubSequence(int **b, char s1[], int i, int j)
{
if (i == 0 || j == 0)
return;
if (b[i][j] == 0)
{
PrintlongestSubSequence(b, s1, i - 1, j - 1);
cout << s1[i-1] << " ";
}
else if(b[i][j]==1)
PrintlongestSubSequence(b, s1, i - 1, j);
else
PrintlongestSubSequence(b, s1, i, j - 1);
}
int longestSubSequence(char s1[], char s2[])
{
int len1 = strlen(s1);
int len2 = strlen(s2);
int **c = new int*[len1 + 1];
int **b = new int*[len1 + 1];
for (int i = 0; i < len1 + 1; i++)
{
c[i] = new int[len2 + 1];
b[i] = new int[len2 + 1];
}
for (int i = 0; i < len1 + 1; i++)
c[i][0] = 0;
for (int j = 0; j < len2 + 1; j++)
c[0][j] = 0;
for (int i = 1; i < len1 + 1; i++)
for (int j = 1; j < len2 + 1; j++)
{
if (s1[i - 1] == s2[j - 1])
{
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 0;//是为了保存结果下标
}
else
{
c[i][j] = max(c[i - 1][j], c[i][j - 1]);
if (c[i - 1][j]>c[i][j - 1])
b[i][j] = 1;
else
b[i][j] = -1;
}
}
PrintlongestSubSequence(b, s1, len1, len2);
return c[len1][len2];
}
扩展:寻找三个串的最长子序列或者子串
http://blog.csdn.net/hackbuteer1/article/details/6686925
最长递增子序列
int LISS(const int array[], size_t length, int result[])
{
int *c=new int[length];//表示以第i个字母作为结束得到的最长递增子串长度
int *pre = new int[length];//以第i个字母作为结束得到的最长递增子串,其前一个元素下标
for (int i = 0; i < length; i++)
{
c[i] = 1;
pre[i] = i;
}
int max = 1,k=0;
//c[i]就是c[j](j=0,1,...,i-1)中满足array[j]<c[i]的子串+1
for (int i = 1; i < length; i++)
{
for (int j = 0; j < i;j++)
if (array[i]>array[j]&&c[i]<c[j]+1) // 如果要求非递减子序列只需将array[j] < array[i]改成 <= ,//如果要求递减子序列只需改为>
{
c[i] = c[j] + 1;
pre[i] = j;
if (c[i] > max)
{
max = c[i];
k = i;
}
}
}
int index = max - 1;
while (pre[k] != k)
{
result[index--] = array[k];
k = pre[k];
}
result[index] = array[k];//最后一个
return max;
}