给定两个字符串,记为start和to,再给定一个字符串列表list,list中一定包含to list中没有重复字符串,所有的字符串都是小写的。
规定: start每次只能改变一个字符,最终的目标是彻底变成to,但是每次变成的新字符串必须在list 中存在。
请返回所有最短的变换路径。
【举例】
start="abc",end="cab",list={"cab","acc","cbc","ccc","cac","cbb","aab","abb"}
转换路径的方法有很多种,但所有最短的转换路径如下:
abc -> abb -> aab -> cab
abc -> abb -> cbb -> cab
abc -> cbc -> cac -> cab
abc -> cbc -> cbb -> cab
思路一:
我们建立一个邻居表,邻居的定义是:一个字符串通过改变一个字符就可以变成另一个字符串,那么另一个字符串就是这个字符的邻居。我们遍历每一个字符串查看后面的字符是否是当前字符串的邻居,即可得到我们需要的邻居表。邻居表的建立需要的时间复杂度为:O(N^2),我们在遍历当前的字符串就可以得到本题答案,算法的整体时间复杂度为:O(N^2*K),其中K表示字符串的长度。
思路二:
同样建立邻居表,不过同思路以不同的。我们把给定的字符串列表list全部放在一个hashmap中,由于本题中通过hashmap查找指定字符串时不能忽略字符串的长度,所以查找字符串的时间复杂度由原来的O(1)转变为O(K)。根据题目我们知道所有的字符串都是小写的所以每个字符的变化只有24种,我们列出开始字符串邻居的所有可能性(时间复杂度为:O(25*k)),在hashmap中查看是否有这种情况的邻居即可。整体的时间复杂度为O(K^2)。
我们还需要建立距离表,其含义是该字符串到开始字符串的距离是多少。
这里我们演示思路二的代码
- public static List
> findMinPaths(String start, String end, List list) {
- list.add(start);
- HashMap
> nexts = getNexts(list); - HashMap
distances = getDistances(start, nexts); - LinkedList
pathList = new LinkedList<>(); - List
> res = new ArrayList<>();
- getShortestPaths(start, end, nexts, distances, pathList, res);
- return res;
- }
-
- public static HashMap
> getNexts(List words) { - Set
dict = new HashSet<>(words); - HashMap
> nexts = new HashMap<>(); - for (int i = 0; i < words.size(); i++) {
- nexts.put(words.get(i), getNext(words.get(i), dict));
- }
- return nexts;
- }
-
- public static ArrayList
getNext(String word, Set dict) { - ArrayList
res = new ArrayList<>(); - char[] chs = word.toCharArray();
- for (char cur = 'a'; cur <= 'z'; cur++) {
- for (int i = 0; i < chs.length; i++) {
- if (chs[i] != cur) {
- char tmp = chs[i];
- chs[i] = cur;
- if (dict.contains(String.valueOf(chs))) {
- res.add(String.valueOf(chs));
- }
- chs[i] = tmp;
- }
- }
- }
- return res;
- }
-
- public static HashMap
getDistances(String start, - HashMap
- ArrayList
> nexts) { - HashMap
distances = new HashMap<>(); - distances.put(start, 0);
- Queue
queue = new LinkedList<>(); - queue.add(start);
- HashSet
set = new HashSet<>(); - set.add(start);
- while (!queue.isEmpty()) {
- String cur = queue.poll();
- for (String next : nexts.get(cur)) {
- if (!set.contains(next)) {
- distances.put(next, distances.get(cur) + 1);
- queue.add(next);
- set.add(next);
- }
- }
- }
- return distances;
- }
-
- private static void getShortestPaths(String cur, String to,
- HashMap
> nexts, - HashMap
distances, - LinkedList
path, - List
> res)
{ - path.add(cur);
- if (to.equals(cur)) {
- res.add(new LinkedList
(path)); - } else {
- for (String next : nexts.get(cur)) {
- if (distances.get(next) == distances.get(cur) + 1) {
- getShortestPaths(next, to, nexts, distances, path, res);
- }
- }
- }
- path.pollLast();
- }
-
- public static void main(String[] args) {
- String start = "abc";
- String end = "cab";
- String[] test = {"cab", "acc", "cbc", "ccc", "cac", "cbb", "aab", "abb"};
- ArrayList
list = new ArrayList<>(); - for (int i = 0; i < test.length; i++) {
- list.add(test[i]);
- }
-
- List
> res = findMinPaths(start, end, list);
- System.out.println(res);
-
- }