P1019单词接龙

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 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 "";/// 如果这两个字符串无法拼接,就返回空串
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值