题目
分析
suffix是后缀,题目的意思是求两个单词的公共后缀的第一个字符的地址。我看有些博客说求的是首个共用结点的地址,我觉得是不对的。
晴神/柳神的解法,是把第一个单词中出现的字母标记,然后遍历第二个单词,出现的首个标记的字母的地址,即为所求。能这样做是因为,只要遇到了某个相同的字母,后面的就一定相同,比如样例1中,只要遇到了a,那么后面的过程都是相同的:
a(00010) -> D(12345) -> i(67890) -> n(00002) -> g(00003)
所以只要遇到了第一个“相同”的字母,后面的路径就会完全一样,也就是两个单词的公共后缀,所以才可以这样做。但是什么叫“相同”?
比如样例2(没看网上博客我还没发现有两个不同地址不同next的a),出现了两个a,这好像有些不合理了,因为即使都碰到了a,但后面的走向不同不能确保相同。所以上面所说的相同,不仅仅是字母(data)相同,还必须是地址相同,比如单词1有个a(00010),单词2有个a(00011),那么这并不算在公共后缀。而上面的解法,由于不同地址的相同字母存储在不同的地方,标记也不同,所以正确运行。
举个例子:
00001 00006 5
00003 i 00004
00006 h 00003
00001 t 00002
00004 s 00005
00002 h 00003
word1(this):t->h(00002)->i->s
word2(his):h(00006)->i->s
所以公共后缀是is
,而不是his
我一开始就没想到上面的做法,而是想把两个单词变成字符串形式,然后从末尾开始遍历,相同就一直递减,直到出现不相同的字符停止,输出分界处字符的地址。代码如下:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int record[100001][2] = { 0 };
int main() {
int addr1, addr2, n;
cin >> addr1 >> addr2 >> n;
for (int i = 0; i < n; i++) {
int addr, next;
char data;
cin >> addr >> data >> next;
record[addr][0] = data;
record[addr][1] = next;
}
int ptr1 = addr1;
int ptr2 = addr2;
string word1, word2;
vector<int> address1, address2; //为解决测试点5而加
while (ptr1 != -1) {
word1 += (char)record[ptr1][0];
address1.push_back(ptr1);
ptr1 = record[ptr1][1];
}
while (ptr2 != -1) {
word2 += (char)record[ptr2][0];
address2.push_back(ptr2);
ptr2 = record[ptr2][1];
}
int i = word1.length() - 1;
int j = word2.length() - 1;
while (word1[i] == word2[j] && address1[i] == address2[j]/*这个条件是关键*/ && i >= 0 && j >= 0) {
i--;
j--;
}
if (i == word1.length() - 1) printf("-1");
else printf("%05d", address1[i+1]);
}
运行时测试点5一直过不了。后来修改了最后一个while循环的条件,添加了address1[i] == address2[j]
,也就是说,碰到了相同字母不算,还得是相同地址的。测试点5才通过。