每周总结第四周
一、题目内容:
大家经常玩成语接龙游戏,我们试一试英语的接龙吧:一个文本文件中有N 个不同的英语单词, 我们能否写一个程序,快速找出最长的能首尾相连的英语单词链,每个单词最多只能用一次。
最长的定义是:最多单词数量,和单词中字母的数量无关。
二、题目要求:
1、统一输入文件名称:input1.txt, input2.txt
2、统一输出文件名称:output1.txt,output2.txt
3、程序需要考虑下列异常状况:
(1)例如,文件不存在,你的程序会崩溃么,还是能优雅地退出并给用户提示信息?
(2)如果文件没有任何单词、只有一个单词、没有可以首尾相连的单词,程序应该如何输出?
(3)如果输入文件有一万个单词,你的程序能多快输出结果?
本题是一道比较经典的图论问题,可以使用回溯法或深度优先搜索来解决。具体来说,可以将单词看成图中的点,如果两个单词的首尾相连,则表示这两个单词之间有一条边,然后问题就转化成了求最长的链的问题。由于本题中最长的定义是最多单词数量,和单词中字母的数量无关,因此可以考虑使用深度优先搜索来解决。
具体算法如下:
-
读入单词列表,建立图结构。
-
对于每个单词,从该单词开始进行深度优先搜索,找到所有可以和该单词首尾相连的单词,标志已经被使用,并将该单词添加到单词链中。
-
每当找到一个新的单词链时,就和已有的单词链进行比较,更新最长单词链。
-
将最长单词链输出到文件中。
- 处理异常情况,例如文件不存在、文件没有单词、没有可以首尾相连的单词等等。
import java.io.*; import java.util.*; public class LongestWordChain { public static void main(String[] args) { List<String> words = readWords("input.txt"); List<String> longestChain = findLongestWordChain(words); if (longestChain.size() == 0) { System.out.println("No word chain found"); } else { System.out.println("Longest word chain found with length " + longestChain.size() + ": " + String.join(" -> ", longestChain)); writeWords("output.txt", longestChain); } } public static List<String> readWords(String filename) { List<String> words = new ArrayList<>(); try (Scanner scanner = new Scanner(new File(filename))) { while (scanner.hasNext()) { words.add(scanner.next()); } } catch (FileNotFoundException e) { System.out.println("ERROR: File " + filename + " not found"); } return words; } public static List<String> findLongestWordChain(List<String> words) { List<String> longestChain = new ArrayList<>(); for (int i = 0; i < words.size(); i++) { String startWord = words.get(i); List<String> chain = new ArrayList<>(); chain.add(startWord); Set<Integer> visited = new HashSet<>(); visited.add(i); if (searchLongestChain(words, visited, chain, longestChain)) { longestChain = new ArrayList<>(chain); } } return longestChain; } public static boolean searchLongestChain(List<String> words, Set<Integer> visited, List<String> chain, List<String> longestChain) { boolean foundLongest = false; String lastWord = chain.get(chain.size() - 1); for (int i = 0; i < words.size(); i++) { if (!visited.contains(i)) { String nextWord = words.get(i); if (isConnected(lastWord, nextWord)) { visited.add(i); chain.add(nextWord); foundLongest = searchLongestChain(words, visited, chain, longestChain); chain.remove(chain.size() - 1); visited.remove(i); } } } if (chain.size() > longestChain.size()) { foundLongest = true; } return foundLongest; } public static boolean isConnected(String word1, String word2) { if (word1.equals(word2)) { return false; } int len1 = word1.length(); int len2 = word2.length(); if (len1 + 1 != len2 && len1 != len2 + 1) { return false; } String shorter = len1 < len2 ? word1 : word2; String longer = len1 < len2 ? word2 : word1; boolean foundMismatch = false; for (int i = 0, j = 0; i < shorter.length(); i++, j++) { if (shorter.charAt(i) != longer.charAt(j)) { if (foundMismatch) { return false; } else { foundMismatch = true; j++; } } } return true; } public static void writeWords(String filename, List<String> words) { try (PrintWriter writer = new PrintWriter(new File(filename))) { for (String word : words) { writer.println(word); } } catch (FileNotFoundException e) { System.out.println("ERROR: File " + filename + " cannot be opened for writing"); } } }
这个java程序包含了三个主要函数:
- readWords 函数读取包含单词的文件,返回一个 String 列表。
- findLongestWordChain 函数接受单词列表,返回最长的单词链。
- writeWords 函数将最长单词链写入文件。
searchLongestChain 函数是递归实现的深度优先搜索,函数使用了 Set 类型存储访问过的单词的下标,用于加速访问和判断是否重复。在搜索中,如果找到一个长度更长的单词链,就将 longestChain 更新为当前单词链。
isConnected 函数用于判断两个单词是否可以首尾相连,这个函数的实现,使用了两个指针 i 和 j 分别在两个单词中移动,一旦发现不一致的字符数量超过 1,就返回 false。
此外,此程序也处理一些异常情况,例如文件不存在或无法打开,无法找到单词链,等等。
注意:使用 Java 时,需要先通过 import 语句导入需要使用的类,例如 Scanner 和 PrintWriter。在导入之后,就可以像上面的代码一样使用这些类来读写文件。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix