面试题 17.22. 单词转换

面试题 17.22. 单词转换

给定字典中的两个词,长度相等。写一个方法,把一个词转换成另一个词, 但是一次只能改变一个字符。每一步得到的新词都必须能在字典中找到。

编写一个程序,返回一个可能的转换序列。如有多个可能的转换序列,你可以返回任何一个。

示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出:
["hit","hot","dot","lot","log","cog"]
示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: []

解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。

方法1:BFS+List

public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
    Queue<String> q = new LinkedList<>();
    q.offer(beginWord);
    Set<String> words = new HashSet<>(wordList);
    Map<String, String> vis = new HashMap<>();//k 存储cur的下一个字符,v 存储cur,逆向存储,遍历的时候正序
    List<String> res = new ArrayList<>();
    vis.put(beginWord, beginWord);
    while (!q.isEmpty()) {
        int size = q.size();
        for (int i = 0; i < size; i++) {
            String cur = q.poll();
            if (cur.equals(endWord)) {//找到了endWord
                res.add(0, endWord);//插入到res的头部位置
                String t = endWord;
                while (!t.equals(beginWord)) {//不断遍历直到找到beginWord
                    t = vis.get(t);
                    res.add(0, t);
                }
                return res;
            }
            List<String> cans = transform(words, cur);//当前cur字符候选的字符
            for (String can : cans) {
                if (!vis.containsKey(can)) {//如果没有被访问到
                    vis.put(can, cur);
                    q.offer(can);
                }

            }
        }
    }
    return new ArrayList<>();
}


/**
 * 生成目标的word的所有潜在的word,
 * 如hit -->ait bit ...zit但是排除了hit本身
 * hit --> hat hbt... hzt但是排除了hit本身
 * words 含有的上面生成的潜在的word进行收集
 *
 * @param words
 * @param word
 * @return
 */
private List<String> transform(Set<String> words, String word) {
    List<String> resList = new ArrayList<>();
    StringBuffer sb = new StringBuffer(word);
    for (int i = 0; i < sb.length(); i++) {
        char tmp = sb.charAt(i);//记录下索引位置下的char,下面的for loop中会剔除掉这个
        for (char c = 'a'; c <= 'z'; c++) {
            if (tmp == c) continue;//word本身
            sb.setCharAt(i, c);//改变i的值
            String canditate = sb.toString();
            //如果words含有canditate,将其加入到结果集中
            if (words.remove(canditate)) resList.add(canditate);
        }
        sb.setCharAt(i, tmp);//结束本轮loop后,恢复原样
    }

    return resList;
}

方法2:BFS+Stack

public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
    Set<String> words = new HashSet<>(wordList);
    Map<String, String> vis = new HashMap<>();
    Queue<String> q = new LinkedList<>();
    q.offer(beginWord);
    vis.put(beginWord, beginWord);
    Stack<String> stk = new Stack<>();//逆序存栈
    while (!q.isEmpty()) {
        int size = q.size();
        for (int i = 0; i < size; i++) {
            String cur = q.poll();
            if (cur.equals(endWord)) {
                stk.push(endWord);
                String t = endWord;
                while (!t.equals(beginWord)) {
                    t = vis.get(t);
                    stk.push(t);
                }
                List<String> res = new ArrayList<>();
                while (!stk.isEmpty()) res.add(stk.pop());//倒出栈元素
                return res;
            }

            for (String next : words) {
                if (isNext(cur, next) && !vis.containsKey(next)) {
                    vis.put(next, cur);
                    q.offer(next);
                }
            }
        }
    }
    return new ArrayList<>();

}


/**
 * 遍历两个相同长度相同的字符,判断是否不相同的字符差1个
 *
 * @param cur  当前字母
 * @param next 候选字母
 * @return
 */
public boolean isNext(String cur, String next) {
    int cnt = 0;
    for (int i = 0; i < cur.length(); i++) {
        if (cur.charAt(i) != next.charAt(i)) cnt++;
    }
    return cnt == 1;
}

方法3:DFS

List<String> res = new ArrayList<>();//结果集
List<String> wordList;//源字母列表
String endWord;//结尾字母
Set<String> vis = new HashSet<>();//标记字符是否被访问过

public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
    this.wordList = wordList;
    this.endWord = endWord;
    res.add(beginWord);
    vis.add(beginWord);
    return dfs(beginWord) ? res : new ArrayList<>();
}


public boolean dfs(String cur) {
    if (cur.equals(endWord)) return true;
    for (String next : wordList) {
        //是当前cur字母的候选字母 & 没有被访问过
        if (isNext(cur, next) && !vis.contains(next)) {
            vis.add(next);//添加结果
            res.add(next);
            if (dfs(next)) return true;
            else {
                res.remove(res.size() - 1);//该next不可选,移除
            }
        }
    }
    return false;
}


public boolean isNext(String cur, String next) {
    int cnt = 0;
    for (int i = 0; i < cur.length(); i++) {
        if (cur.charAt(i) != next.charAt(i)) cnt++;
    }
    return cnt == 1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值