题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastbeastbeast和astonishastonishastonish,如果接成一条龙则变为beastonishbeastonishbeastonish,另外相邻的两部分不能存在包含关系,例如atatat 和 atideatideatide 间不能相连。
输入格式
输入的第一行为一个单独的整数nnn (n≤20n \le 20n≤20)表示单词数,以下nnn 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式
只需输出以此字母开头的最长的“龙”的长度
输入输出样例
输入 #1
5
at
touch
cheat
choose
tact
a
输出 #1
23
说明/提示
(连成的“龙”为atoucheatactactouchoose)
解题思路
DFS暴力解
找到一个可以作为头的字符串然后与其他字符串不断拼接,直到无法拼接位置
无法拼接的情况:字符串用过2次,两个字符串之间有包含关系,拼接后的字符串是空的;
有情况是字符串虽然没有拼接完但是也是最长的。
package search;
import java.util.Arrays;
import java.util.Scanner;
public class P1019 {
static int n, max,arr[];// max记录拼接后的最长字符串的长度, arr[]记录每个字符串的使用次数
static String sArr[], head;// sArr存储n个字符串,head代表头字母
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 接收数据
n = sc.nextInt();
arr = new int[n];
sArr = new String[n];
for (int i = 0; i < n; i++) {
sArr[i] = sc.next();
}
head = sc.next();
for (int i = 0; i < n; i++) {// 遍历每一个字符串看看哪些可以作为开头
if (sArr[i].charAt(0) == head.charAt(0)) {
arr[i] = 1;// 如果可以作为开头,就用这个并把其置为已经使用了一次
dfs(sArr[i]);//开始用这个开头搜
Arrays.fill(arr, 0);//每次以一个开头搜完记得把记录每个字符串使用次数的数组arr全置为0,以供下一次使用
}
}
System.out.println(max);
}
/**
*
* @param headString 作为开头的字符串
*/
public static void dfs(String headString) {
for (int i = 0; i < n; i++) {// 遍历每一个字符串,看看哪个可以拼接
if (arr[i] == 2) {// 如果该字符串已经用过两次,那么continue
continue;
}
if (headString.length()>max) {//有可能该头字符串匹配不到任何字符串,但它本身的长度就是最大的
max = headString.length();
}
String s = stitching(headString, sArr[i]);// s代表拼接完成后的字符串
if (s == "") {//如果字符串是空的,continue即可
continue;
}
//如果拼接后的字符串和原来的字符串长度有相同的,那就说明其中有字符串被包含,直接continue即可
if (s.length() == headString.length() || s.length() == sArr[i].length()) {
continue;
}
if (s.length()>max) {//如果拼接后的字符串长度大于max
max = s.length();
}
arr[i]++;
dfs(s);//进行下一次拼接,以已经拼接好的字符串为头
arr[i]--;//回溯:拼好后要把相应字符串所用次数减一,以便其余拼接方法使用
}
}
// 写一个方法拼接字符串
/**
* 要使字符串长度尽量大,那么只要headString的末尾和tailString的开头有相同的字符,就进行拼接
*
* @param headString 待拼接的放在前面的字符串
* @param tailString 待拼接的放在后面的字符串
* @return 能拼接成功就返回拼接后的字符串,没拼接成功就返回空串
*/
public static String stitching(String headString, String tailString) {
// 前者后缀匹配后者前缀
int a = headString.length() - 1;
int b = 1;
while (a >= 0 && b <= tailString.length() - 1) {// 只要不超出各自的长度就一直找,直到找到可以匹配的字符为止
if (headString.substring(a, headString.length()).equals(tailString.substring(0, b))) {
// 要使字符串长度尽量,因此一旦匹配到就直接return
return headString + tailString.substring(b, tailString.length());
}
a--;// a前移
b++;// b后移
}
return "";/// 如果这两个字符串无法拼接,就返回空串
}
}