面試小結
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;
}