每周总结第四周

本周完成了算法作业:
 
课堂练习01题目:计算最长英语单词链。

一、题目内容:

大家经常玩成语接龙游戏,我们试一试英语的接龙吧:一个文本文件中有N 个不同的英语单词, 我们能否写一个程序,快速找出最长的能首尾相连的英语单词链,每个单词最多只能用一次。

最长的定义是:最多单词数量,和单词中字母的数量无关。

二、题目要求:

1、统一输入文件名称:input1.txt, input2.txt

2、统一输出文件名称:output1.txt,output2.txt

3、程序需要考虑下列异常状况:

(1)例如,文件不存在,你的程序会崩溃么,还是能优雅地退出并给用户提示信息?

(2)如果文件没有任何单词、只有一个单词、没有可以首尾相连的单词,程序应该如何输出?

(3)如果输入文件有一万个单词,你的程序能多快输出结果?

 

本题是一道比较经典的图论问题,可以使用回溯法或深度优先搜索来解决。具体来说,可以将单词看成图中的点,如果两个单词的首尾相连,则表示这两个单词之间有一条边,然后问题就转化成了求最长的链的问题。由于本题中最长的定义是最多单词数量,和单词中字母的数量无关,因此可以考虑使用深度优先搜索来解决。

具体算法如下:

  1. 读入单词列表,建立图结构。

  2. 对于每个单词,从该单词开始进行深度优先搜索,找到所有可以和该单词首尾相连的单词,标志已经被使用,并将该单词添加到单词链中。

  3. 每当找到一个新的单词链时,就和已有的单词链进行比较,更新最长单词链。

  4. 将最长单词链输出到文件中。

  5. 处理异常情况,例如文件不存在、文件没有单词、没有可以首尾相连的单词等等。           

 

复制代码
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。在导入之后,就可以像上面的代码一样使用这些类来读写文件。

posted @   神行乌龟  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示