我自己采用的是第一种写法,然后提交之后就是测试2和4答案错误,百思不得其解,各种搜索,搜出来的都是结构体数组+标志位+两次遍历,这个一会再说,既然没办法解决问题,那我就放弃这个思路吧,偏偏这个时候让我看到一个人的评论,他的思路和我竟然一样,点进去看他的那篇博客,我开心了好久,因为他的代码竟然AC了,但我的没有,为什么,就是因为他采用的是我上面提到的第二种写法(也就是代码中注释了的那部分)。
于是我就开始自闭了,按照分析,这个count数组中应该只有一个位置是2,这个地址应该是唯一的才对,所以不管是第一种写法(找到出现两次的地址就输出)还是第二中写法(全部遍历一次,最后得到的是最后一个出现两次的地址)应该是相同结果,但事实就是第二种写法AC,第一种写法答案错误。我不知道这个测试用例是什么样的,所以没办法确定这两种写法是否针对某个特殊用例具有不同结果。
但好在我的一个同学给出我举出一个例子,推翻了这个思路(不管方式一还是方式二都是错的)。比如 being 和 ing,答案应该是输出 i 的地址,
测试用例可以是 11111 22222 5 11111 b 12345 12345 e 22222 22222 i 00003 00003 n 00004 00004 g -1但是按我这种思路,对于i的地址22222,count[22222]根本不会得到2,因为22222一次出现在address的位置,一次出现在nextAddress的位置,而我count统计的是nextAddress位置,所以,这种思路只能输出 -1。
这就是我自闭的一下午,至于那个人的写法为什么会AC,反正我不明白,可能因为测试用例中没有出现我举出的这种例子吧。
2. 普遍的正确思路
也就是所谓的 结构体数组+标志位+两次遍历,用结构体保存每个节点,节点字段包括 内容(字符),下一个节点的地址,标志位(是否已访问),用一个数组存储全部节点,节点的地址作为数组下标。
首先从第一个单词的开始节点(地址)出发,顺着链表逐个访问节点,并将遍历到的节点的标志位置为;再从第二个单词的开始节点(地址)出发,顺着链表逐个访问节点,如果途中遇到某个节点的标志位已经置位,说明从这个节点往后都是它两的公共部分,如果链表全部节点都没有置位,说明这两个单词没有公共后缀输出-1。
#include <iostream> using namespace std; struct Node { char data; // 值 int nextid; // 下个节点 bool visit; // 是否访问过 }node[100000]; int main() { int s1, s2, n; cin >> s1 >> s2 >> n; int id; char data; int nextid; for (int i = 0; i < n; ++i) { cin >> id >> data >> nextid; // 创建新节点 node[id] = {data, nextid, false}; } // 按照第一个单词,节点都访问一遍,比较为true for (int i = s1; i != -1; i = node[i].nextid) { node[i].visit = true; } // 按照第二个单词,再遍历,若碰到一个visit为true的节点说明后面和第一个单词一样了 // 当前节点就是公共后缀的第一个节点 for (int i = s2; i != -1; i = node[i].nextid) { if(node[i].visit == true) { printf("%05d", i); return 0; } } // 否则就有没有公共后缀 printf("-1"); return 0; }