1. 程式人生 > >[LeetCode]Word Ladder,解題報告

[LeetCode]Word Ladder,解題報告

目錄

題目

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

Given:
start = “hit”
end = “cog”
dict = [“hot”,”dot”,”dog”,”lot”,”log”]
As one shortest transformation is “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
return its length 5.

Note:

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

思路

這道題目本身不難,但是很考察每個做題人的抽象能力。因為之前我在《程式設計之美》上看到過這個題目,所以我很快的能把這道題跟多叉樹聯絡在一起。

我們假設start字串為多叉樹的根節點,end字串為多叉樹最後的葉子節點。那當start字串改變其中一個字元形成的新字串new,並且new屬於dict字典當中,那new字串就是start的第一個子節點。其他節點以此類推。

當我們把這道題目想成一個多叉樹之後,接下來我們要做的就是從根節點開始,找一條能走到end節點的路徑。遍歷的方法有:BFS和DFS,從時間角度考慮,我們當然選擇BFS。

AC程式碼

有人在明白了抽象成多叉樹之後,依然可能面臨TLE的問題。

原因:通常我們入佇列的方式是從dict字典裡選一個字串,判斷和當前字串是否相差一個字元,是則入佇列,不是,則不入佇列。這樣的時間複雜度是O(n),n是字典的數量。當n很大時,就容易TLE。

解決方案:我們可以換一種思路,英文字母一共26個,當前字串的長度是L,所以我們用26個英文字母對當前字串的每個字元挨個替換,看形成的新字串是否在字典中。是則入佇列,不是則不入佇列。這樣的時間複雜度是:O(L* 26)。這樣親測,不超時。

public class Solution {
    public static int ladderLength(String start, String end, Set<String> dict) {
        int dist = calDistance(start, end);
        if (dist == 1) {
            return 2;
        }

        return bfsDict(dict, start, end);
    }

    private static int calDistance(String word1, String word2) {
        int dist = 0;

        for (int i = 0; i < word1.length(); i++) {
            if (word1.charAt(i) != word2.charAt(i)) {
                dist += 1;
            }
        }

        return dist;
    }

    private static void enQueue(Set<String> dict, LinkedList<String> queue, String target, Map<String, Integer> map, int step) {
        if (dict == null || dict.isEmpty()) {
            return;
        }

        for (int i = 0; i < target.length(); i++) {
            for (char c = 'a'; c <= 'z'; c++) {
                StringBuilder sBuilder = new StringBuilder(target);
                if (sBuilder.charAt(i) == c) {
                    continue;
                }
                sBuilder.setCharAt(i, c);
                if (dict.contains(sBuilder.toString())) {
                    queue.addLast(sBuilder.toString());
                    dict.remove(sBuilder.toString());
                    map.put(sBuilder.toString(), step + 1);
                }
            }
        }
    }

    private static int bfsDict(Set<String> dict, String start, String end) {
        LinkedList<String> queue = new LinkedList<String>();
        Map<String, Integer> hashMap = new HashMap<String, Integer>();
        enQueue(dict, queue, start, hashMap, 1);

        while (!queue.isEmpty()) {
            String word = queue.poll();
            int step = hashMap.get(word);
            if (calDistance(word, end) == 1) {
                return step + 1;
            }

            enQueue(dict, queue, word, hashMap, step);
        }

        return 0;
    }
}