lintcode 单词接龙II

简介: 题意   给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列   比如:     1、每次只能改变一个字母。     2、变换过程中的中间单词必须在字典中出现。

题意

  给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列

  比如:

    1、每次只能改变一个字母。

    2、变换过程中的中间单词必须在字典中出现。

注意事项

  • 所有单词具有相同的长度。
  • 所有单词都只包含小写字母。

样例

  给出数据如下:

  start = "hit"

  end = "cog"

  dict = ["hot","dot","dog","lot","log"]

  返回

  [

      ["hit","hot","dot","dog","cog"],

      ["hit","hot","lot","log","cog"]

    ]

 

解题思路

  根据每两个单词是否只差一个字母,进行建图,然后如下。

  1.深搜 + 回溯 + 记忆化(记录每个节点到 终结点 的最短转换序列),超时啦。。。

  2.通过广搜 计算出终结点到各个节点的最短距离(包括源节点到终结点的最短距离,也就是和 最短转换序列的长度对应)

public class Solution {
    /**
     * @param start, a string
     * @param end,   a string
     * @param dict,  a set of string
     * @return a list of lists of string
     */
    public List<List<String>> findLadders(String start, String end, Set<String> dict) {
        // write your code here
        Map<String, List<String>> g = new HashMap<>();
        Set<String> words = new HashSet<>(dict);
        words.add(start);
        words.add(end);

        String[] wordArray = words.toArray(new String[0]);
        for (int i = 0; i < wordArray.length - 1; ++i) {
            for (int j = i + 1; j < wordArray.length; ++j) {
                String first = wordArray[i], second = wordArray[j];
                if (this.wordDiffCnt(first, second) == 1) {
                    if (!g.containsKey(first)) {
                        List<String> newList = new ArrayList<>();
                        g.put(first, newList);
                    }
                    g.get(first).add(second);

                    if (!g.containsKey(second)) {
                        List<String> newList = new ArrayList<>();
                        g.put(second, newList);
                    }
                    g.get(second).add(first);
                }
            }
        }

        resultMap = new HashMap<>();
        visit = new HashSet<>();

//      return dfs(g, start, end);//超时了,不知道怎么优化

        List<List<String>> result = new ArrayList<>();
        dist = new HashMap<>();
        dfs(result, new LinkedList<String>(), g, start, end, bfs(g, end, start));
        return result;
    }

    //通过bfs计算 终结点 到 源结点 的最短转换长度,以及 终结点到各个结点的最短距离(在通过 dfs寻找 最短转换序列的时候用到)
    private Map<String, Integer> dist;
    private int bfs(Map<String, List<String>> g, String start, String end) {
        Queue<String> queue = new LinkedList<>();
        visit.add(start);
        queue.add(start);
        dist.put(start, 1);
        int minLen = 0;
        while(!queue.isEmpty()) {
            start = queue.poll();

            if(start.equals(end)) {
                if(minLen == 0) {
                    minLen = dist.get(start);
                }
            }

            if(g.containsKey(start)) {
                for (String next : g.get(start)) {
                    if(visit.contains(next)) continue;
                    visit.add(next);
                    queue.add(next);
                    dist.put(next, dist.get(start)+1);
                }
            }
        }
        visit.clear();
        return minLen;
    }

    private void dfs(List<List<String>> result, List<String> tmp, Map<String, List<String>> g, String start, String end, int minLen) {

        if(tmp.size()+dist.get(start)-1 >= minLen) return;

        if (start.equals(end)) {
            result.add(new ArrayList<>(tmp));
            result.get(result.size() - 1).add(end);
            return;
        }

        visit.add(start);
        tmp.add(start);
        if (g.containsKey(start)) {
            for (String next : g.get(start)) {
                if(visit.contains(next)) continue;
                dfs(result, tmp, g, next, end, minLen);
            }
        }
        visit.remove(start);
        tmp.remove(tmp.size()-1);
    }

    @Deprecated
    private List<List<String>> dfs(Map<String, List<String>> g, String start, String end) {
        List<List<String>> result = new ArrayList<>();
        if (start.equals(end)) {
            List<String> list = new ArrayList<>();
            list.add(end);
            result.add(list);
            resultMap.put(end, result);
            return result;
        }

        if (resultMap.containsKey(start)) {
            return resultMap.get(start);
        }

        if (!g.containsKey(start)) {
            resultMap.put(start, null);
            return null;
        }

        visit.add(start);

        List<List<String>> nextResult = new ArrayList<>();

        int minLen = Integer.MAX_VALUE;
        for (String next : g.get(start)) {
            if(visit.contains(next)) continue;
            List<List<String>> tmp = dfs(g, next, end);
            if (tmp != null) {
                for (List<String> list : tmp) {
                    if(minLen > list.size()) minLen = list.size();
                    nextResult.add(list);
                }
            }
        }

        visit.remove(start);

        for (List<String> list : nextResult) {
            if (list.size() == minLen) {
                List<String> tmp = new LinkedList<>(list);
                tmp.add(0, start);
                result.add(tmp);
            }
        }
        if(result.size() > 0) {
            resultMap.put(start, result);
        }
        return result;
    }

    //记忆化搜索 每个节点到终点的最小步数的路径
    private Map<String, List<List<String>>> resultMap;
    //每个节点的访问的情况
    private Set<String> visit;

    private int wordDiffCnt(String s1, String s2) {
        int diffCnt = 0;
        for (int i = 0; i < s1.length(); ++i) {
            if (s1.charAt(i) != s2.charAt(i)) {
                ++diffCnt;
            }
        }
        return diffCnt;
    }
}

 

 

 

目录
相关文章
|
人工智能 机器人 测试技术
【python】两数之和 python实现(详细讲解)
【python】两数之和 python实现(详细讲解)
|
存储 人工智能 vr&ar
【AI系统】CPU 基础
CPU,即中央处理器,是计算机的核心组件,负责执行指令和数据计算,协调计算机各部件运作。自1946年ENIAC问世以来,CPU经历了从弱小到强大的发展历程。本文将介绍CPU的基本概念、发展历史及内部结构,探讨世界首个CPU的诞生、冯·诺依曼架构的影响,以及现代CPU的组成与工作原理。从4004到酷睿i系列,Intel与AMD的竞争推动了CPU技术的飞速进步。CPU由算术逻辑单元、存储单元和控制单元三大部分组成,各司其职,共同完成指令的取指、解码、执行和写回过程。
819 3
|
存储 缓存 前端开发
如何优化 SSR 应用以减少服务器压力
优化SSR应用以减少服务器压力,可采用代码分割、缓存策略、数据预加载、服务端性能优化、使用CDN、SSR与SSG结合、限制并发请求、SSR与CSR平滑切换、优化前端资源及利用框架特性等策略。这些方法能有效提升性能和稳定性,同时保证用户体验。
385 4
|
存储 Kubernetes 算法
ID生成服务系列(一)
ID生成服务系列(一)
|
存储 安全 Java
aqs原理初探以及公平锁和非公平锁实现
aqs原理初探以及公平锁和非公平锁实现
504 0
|
9月前
|
人工智能 自然语言处理 搜索推荐
阿里云 AI 搜索开放平台集成 DeepSeek 模型
阿里云 AI 搜索开放平台最新上线 DeepSeek -R1系列模型。
478 2
|
监控 IDE Java
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
如何在无需重新启动服务器的情况下在 Spring Boot 上重新加载我的更改?
1150 8
|
关系型数据库 MySQL C语言
源码安装MySQL8.0 1
源码安装MySQL8.0
342 0
|
JavaScript
Vue3标签(Tag)
这是一个Vue组件`Tag.vue`,提供了多样化的标签展示功能。支持设置标签颜色、尺寸、图标、边框等样式,并可实现标签的动态添加与删除。
267 2
Vue3标签(Tag)
|
NoSQL Java Redis
springboot整合redis
这篇文章介绍了如何在Spring Boot中整合Redis,包括搭建Redis环境、添加依赖、创建实体类、控制器以及配置文件,并说明了在连接Redis时需要启动Redis服务。
springboot整合redis