5 个字符长度的单词,4565 个中间单词的测试过了,在我的电脑上大概 400ms 左右,分享下代码:
- 中间单词数: 4565
- 总耗时: 387.973248ms
- 展开树耗时: 386.685609ms
- 拼接结果耗时: 0.390396ms
- 临时测试代码算法耗时: 0.0ms
- 临时测试计数器: 0
- [nanny, canny, candy, sandy, sands, sends, seeds, sleds, slews, clews, clefs, cleft, cleat, bleat, bloat, float, flout, clout, cloud, aloud]
- [nanny, danny, dandy, sandy, sands, sends, seeds, sleds, slews, clews, clefs, cleft, cleat, bleat, bloat, float, flout, clout, cloud, aloud]
- end
复制代码- public class Solution {
- private List<List<String>> results;
- private List<String> result;
-
- /**
- * 寻找最短的转换路径
- *
- * @param beginWord 开头单词
- * @param endWord 结尾单词
- * @param wordList 中间单词列表
- * @return 最短路径列表
- */
- public List<List<String>> findLadders(final String beginWord, final String endWord, final Set<String> wordList) {
- // 结果
- this.results = new ArrayList<>();
- //Main.expandTreeTiming.startTiming();
- // 最大展开次数
- int maxLen = wordList.size() + 1;
- // 移除与开头单词重复的中间单词
- wordList.remove(beginWord);
- // 将结尾单词添加到单词列表
- wordList.add(endWord);
-
- // 上一级节点列表
- Map<String, TreeNode<String>> lastNodes = new HashMap<>(1);
- // 将首个单词加入
- lastNodes.put(beginWord, new TreeNode<>(beginWord));
- // 按照中间单词数循环,如果在某个长度找到了可以转换的路径,则不再尝试下一个长度
- int len = 1;
- while(!lastNodes.containsKey(endWord) && len <= maxLen) {
- // 当前级节点列表
- Map<String, TreeNode<String>> currentNodes = new HashMap<>();
- // 展开上一级树
- for (final TreeNode<String> node : lastNodes.values()) {
- String word = node.getValue();
- // 遍历未使用过的单词
- for (final String key : wordList) {
- // 如果两个单词可以互相转换
- if (this.hasConversion(word, key)) {
- // 如果已经存在这个单词,则在其所属节点增加一个父节点,否则新建一个子节点
- if(currentNodes.containsKey(key)) {
- node.addChildNode(currentNodes.get(key));
- } else {
- TreeNode<String> keyNode = new TreeNode<>(key);
- node.addChildNode(keyNode);
- currentNodes.put(key, keyNode);
- }
- }
- }
- }
- // 用当前级节点列表覆盖上一级节点列表
- lastNodes = currentNodes;
- // 移除已使用过的中间单词
- wordList.removeAll(currentNodes.keySet());
-
- // 继续搜寻更长的路径
- len += 1;
- }
- // Main.expandTreeTiming.stopTiming();
- // Main.resultTiming.startTiming();
- TreeNode<String> endNode = lastNodes.get(endWord);
- if(endNode != null) {
- this.result = new ArrayList<>(len);
- this.result.add(endWord);
- for(int i = 1; i < len; i++) {
- this.result.add(null);
- }
- this.addResults(endNode.getParentNodes().iterator(), 1);
- }
- // Main.resultTiming.stopTiming();
- // 返回结果
- return this.results;
- }
-
- private void addResults(Iterator<TreeNode<String>> it, int index) {
- while(it.hasNext()) {
- TreeNode<String> node = it.next();
- this.result.set(index, node.getValue());
-
- List<TreeNode<String>> parentList = node.getParentNodes();
- if(parentList.isEmpty()) {
- List<String> result = new ArrayList<>(this.result);
- Collections.reverse(result);
- this.results.add(result);
- } else {
- addResults(parentList.iterator(), index + 1);
- }
- }
- }
-
- /**
- * 判断两个单词之间能否进行转换
- *
- * @param formWord 源单词
- * @param toWord 目标单词
- * @return 能否进行转换
- */
- private boolean hasConversion(final String formWord, final String toWord) {
- for (int i = formWord.length() - 1, difference = 0; i >= 0; i--) {
- if (formWord.charAt(i) != toWord.charAt(i)) {
- difference += 1;
- if (difference > 1) {
- return false;
- }
- }
- }
- return true;
- }
- // =============
- /**
- * 多叉树节点<br>
- *
- * @author cat73
- */
- public class TreeNode<T> {
- /**
- * 当前节点的值
- */
- private final T value;
- /**
- * 父节点列表
- */
- private List<TreeNode<T>> parentNode;
- /**
- * 子节点列表
- */
- private List<TreeNode<T>> childNodes;
- /**
- * 构造一个多叉树节点
- *
- * @param value 当前节点的值
- */
- public TreeNode(final T value) {
- this.value = value;
- }
- /**
- * 获取当前节点的值
- *
- * @return 当前节点的值
- */
- public T getValue() {
- return this.value;
- }
- /**
- * 获取父节点列表
- *
- * @return parentNode 当前节点所属的父节点列表
- */
- public List<TreeNode<T>> getParentNodes() {
- if (this.parentNode == null) {
- this.parentNode = new ArrayList<>();
- }
- return this.parentNode;
- }
-
- /**
- * 添加一个父节点
- *
- * @param childNode 要被添加的父节点
- */
- private void addParentNode(TreeNode<T> parentNode) {
- if (this.parentNode == null) {
- this.parentNode = new ArrayList<>();
- }
- this.parentNode.add(parentNode);
- }
- /**
- * 获取子节点列表
- *
- * @return parentNode 当前节点所属的父节点列表
- */
- public List<TreeNode<T>> getChildNodes() {
- if (this.childNodes == null) {
- this.childNodes = new ArrayList<>();
- }
- return this.childNodes;
- }
-
- /**
- * 添加子节点(会同时在子节点增加父节点)
- *
- * @param childNode 要被添加的子节点
- */
- public void addChildNode(final TreeNode<T> childNode) {
- if (this.childNodes == null) {
- this.childNodes = new ArrayList<>();
- }
- this.childNodes.add(childNode);
- childNode.addParentNode(this);
- }
- }
- }
复制代码 |